Java中的hashCode()是如何实现的?

转载自:http://blog.csdn.net/kevin_ut/article/details/8177783

Java library里本身就对基本的数据类型进implement了不同的hashCode()。要注意的一点是,java 中的 hashCode() 是 int 类型,在64-bit的系统里,int 就只有32位,所以一些用64-bit的大数据类型(如Long)就要经过一些压缩处理,才能转成 int 类型hashCode。这点很重要,也是为什么Integer 和 Long 类的hashCode() implementation不同的原因。

我阅读了library的源代码后,按照不同的数据类型,总结一下,

1. 对简单的primitive data types, 像double, int, char等类型, 由于它们不是Object, 所以它们没有hashCode()的方法,这样写code是会有compile error的:

  1. int a = 2;  
  2. System.out.print( "int a = 2.hashCode()= " );  
  3. System.out.println(a.hashCode());  

       
2. 对于各自primitive data types的wrapper class,例如Integer, Double,  Character等等,它们各自的hashCode() implementation也不一样,我写了如下的总结:

Java Wrapper Class hashCode() implementation Summary
 
Wrapper Class hashCode() implementationNote
Booleanreturn  1231 or 1237;1231 和 1237 是两个相对较大的质数,请看这里: http://stackoverflow.com/questions/3912303/boolean-hashcode
Bytereturn the byte value ranging from -128 to 127由于Byte类型的所有信息都存在了低32位中,所以直接返回wrapped的value (converted 成了int 以后的值)
Characterreturn the character ASCII code由于Character类型的所有信息都存在了低32位中,所以直接返回wrapped的value (converted 成了int 以后的值)
Shortreturn the short value由于Short类型的所有信息都存在了低32位中,所以直接返回wrapped的value (converted 成了int 以后的值)
Integerreturn the int value直接返回wrapped的value (converted 成了int 以后的值)
Longreturn (int)(value ^ (value >>> 32));由于最后的hashCode的类型是int,  而int只有32位,所以64位的Long值,要砍掉一半。为了不失去一半的信息,这个expression的意思是,会值的高32位和低32位的值进行exclusive OR的结果,这样就保证结果均会受前后32位的影响,不会丢失信息。如果直接把Long转成int, 那就会丢掉高32位的信息,这就不是好的implementation
Floatreturn floatToIntBits(value);把float 转成bits, 具体的implementation是我不是太懂,大概是把32位的float 直接当成int输出来,不管那些位置信息,例如本来第31位是符号位,第23到30位代表的是指数,但转成int值后,这些值代表的意义都不存在了,仅仅作为普通的int数位。
Doublebits = doubleToLongBits(value);

        return (int)(bits ^ (bits >>> 32));
第一段code与 floatToIntBits(value) 一样

第二段code是与Long.hashCode()一样
Strings[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]s[i] is the ith character of the string;  why use 31? http://stackoverflow.com/questions/299304/why-does-javas-hashcode-in-string-use-31-as-a-multiplier

这个公式保证String里的第一个character都对最后产生的 hashcode 有所影响
 

3. 自定义的class, 如果override了equals()方法,那么就一定要override hashCode()方法,具体方法请看

Some FAQs:

Q1. 为何hashCode会是int而不是long呢?

答:因为在java中,一个Array的最大长度是: Integer.MAX_VALUE ( http://stackoverflow.com/questions/4166195/why-objecthashcode-returns-int-instead-of-long

Q2. fundamental question(白痴问题): 为什么Object class会有这个hashCode() ?Object 的 hashCode() 常用在什么地方?

答: hashCode()的本意是一个用来唯一标识object的一个code,可以把它当作加密后的密文。常用在Java自带的HashMap或HashTable的data structure 中。

Q3. Object.hashCode() 是如何实现的?

Here is the link that explains how the Object.hashCode() is implemented:  http://stackoverflow.com/questions/2427631/how-is-hashcode-calculated-in-java
And also this:  http://mindprod.com/jgloss/hashcode.html#OBJECT

1. 把某个非零常数值,比如说17,保存在一个叫result的int类型的变量中。   
  2. 对于对象中每一个关键域f(指equals方法中考虑的每一个域),完成以下步骤:   
  a. 为该域计算int类型的散列码c:   
  i. 如果该域是boolean类型,则计算(f ? 0 : 1)   。   
  ii. 如果该域是byte、char、short或者int类型,则计算(int)   f。   
  iii. 如果该域是long类型,则计算(int)   (f^(f>>>32))。   
  iv. 如果该域是float类型,则计算Float.floatToIntBits(f)。   
  v.   如果该域是double类型,则计算Double.doubleToLongBits(f)得到一个long类型的值,然后  按照步骤2.a        .iii,对该long型值计算散列值。   
  vi.如果该域是一个对象引用,并且该类的equals方法通过递归调用equals的方式来比较这个域,则同样对这个域递归调用hashCode。如果要求一个更为复杂的比较,则为这个域计算一个“规范表示(canonical representation)”,然后针对这个范式表示调用hashCode。如果这个域的值为null,则返回0(或者其他某个常数,但习惯上使用0)。   
  vii.   如果该域是一个数组,则把每一个元素当做单独的域来处理。也就是说,递归地应用上述规则,对每个重要的元素计算一个散列码,然后根据步骤2.b中的做法把这些散列值组合起来。   
  b.按照下面的公式,把步骤a中计算得到的散列码c组合到result中:result   =result*37+c   
  3.返回result。   
  4.写完了hashCode方法之后,问自己“是否相等的实例具有相等的散列码”。如果不是的话,找出原因,并修正错误。   
  例如   
  public int hashCode()   
  {   
      int   result   =17;   
      result=result*37   +   width;   
      result=result*37   +   height;   
      return   result;     
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值