zoukankan      html  css  js  c++  java
  • Java学习(十五):hashCode的作用

    1、hashCode的存在主要是用于查找的快捷性,如Hashtable,HashMap等,hashCode是用来在散列存储结构中确定对象的存储地址的;

    2、如果两个对象相同,就是适用于equals(java.lang.Object) 方法,那么这两个对象的hashCode一定要相同;

    3、如果对象的equals方法被重写,那么对象的hashCode也尽量重写,并且产生hashCode使用的对象,一定要和equals方法中使用的一致,否则就会违反上面提到的第2点;

    4、两个对象的hashCode相同,并不一定表示两个对象就相同,也就是不一定适用于equals(java.lang.Object) 方法,只能够说明这两个对象在散列存储结构中,如Hashtable,他们“存放在同一个篮子里”。

    5、hashCode是用于查找使用的,而equals是用于比较两个对象的是否相等的。

    6、hashCode方法的常规协定:如果根据 equals(Object) 方法,两个对象是相等的,那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。

    7、equals方法不等,并不一定要求hashCode也不想等;但为不相等的对象生成不同整数结果可以提高哈希表的性能。

    Google首席Java架构师Joshua Bloch在他的著作《Effective Java》中提出了一种简单通用的hashCode算法

    1. 初始化一个整形变量,为此变量赋予一个非零的常数值,比如int result = 17;

    2. 选取equals方法中用于比较的所有域,然后针对每个域的属性进行计算:

      (1) 如果是boolean值,则计算f ? 1:0

      (2) 如果是bytecharshortint,则计算(int)f

      (3) 如果是long值,则计算(int)(f ^ (f >>> 32))

      (4) 如果是float值,则计算Float.floatToIntBits(f)

      (5) 如果是double值,则计算Double.doubleToLongBits(f),然后返回的结果是long,再用规则(3)去处理long,得到int

      (6) 如果是对象应用,如果equals方法中采取递归调用的比较方式,那么hashCode中同样采取递归调用hashCode的方式。  否则需要为这个域计算一个范式,比如当这个域的值为null的时候,那么hashCode 值为0

      (7) 如果是数组,那么需要为每个元素当做单独的域来处理。如果你使用的是1.5及以上版本的JDK,那么没必要自己去    重新遍历一遍数组,java.util.Arrays.hashCode方法包含了8种基本类型数组和引用数组的hashCode计算,算法同上,

      java.util.Arrays.hashCode(long[])的具体实现:

     1 public static int hashCode(long a[]) {  
     2         if (a == null)  
     3             return 0;  
     4   
     5         int result = 1;  
     6         for (long element : a) {  
     7             int elementHash = (int)(element ^ (element >>> 32));  
     8             result = 31 * result + elementHash;  
     9         }  
    10   
    11         return result;  
    12 } 
     

    Arrays.hashCode(...)只会计算一维数组元素的hashCode,如果是多维数组,那么需要递归进行hashCode的计算,那么就需要使用Arrays.deepHashCode(Object[])方法。

    3. 最后,要如同上面的代码,把每个域的散列码合并到result当中:result = 31 * result + elementHash;

    4. 测试,hashCode方法是否符合文章开头说的基本原则,这些基本原则虽然不能保证性能,但是可以保证不出错。

    5. 为什么每次需要使用乘法去操作result? 主要是为了使散列值依赖于域的顺序,还是上面的那个例子,Test t = new Test(1, 0)跟Test t2 = new Test(0, 1), t和t2的最终hashCode返回值是不一样的。

    6. 为什么是31? 31是个神奇的数字,因为任何数n * 31就可以被JVM优化为 (n << 5) -n,移位和减法的操作效率要比乘法的操作效率高的多。

  • 相关阅读:
    zabbix_agent 主动模式配置
    zabbix 监控ipmi
    超级详细全截图化VMware 安装ubantu
    docker 部署
    C# DataTable和List转换操作类
    C#类型转换工具类
    C# 注册windows 服务
    C# wsdl.exe 生成类文件
    visual studio code download url
    c# xml序列化和反序列化
  • 原文地址:https://www.cnblogs.com/moleme/p/4420007.html
Copyright © 2011-2022 走看看