转载自: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不同的原因。
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的:
- int a = 2;
- System.out.print( "int a = 2.hashCode()= " );
- System.out.println(a.hashCode());
2. 对于各自primitive data types的wrapper class,例如Integer, Double, Character等等,它们各自的hashCode() implementation也不一样,我写了如下的总结:
Wrapper Class | hashCode() implementation | Note |
Boolean | return 1231 or 1237; | 1231 和 1237 是两个相对较大的质数,请看这里: http://stackoverflow.com/questions/3912303/boolean-hashcode |
Byte | return the byte value ranging from -128 to 127 | 由于Byte类型的所有信息都存在了低32位中,所以直接返回wrapped的value (converted 成了int 以后的值) |
Character | return the character ASCII code | 由于Character类型的所有信息都存在了低32位中,所以直接返回wrapped的value (converted 成了int 以后的值) |
Short | return the short value | 由于Short类型的所有信息都存在了低32位中,所以直接返回wrapped的value (converted 成了int 以后的值) |
Integer | return the int value | 直接返回wrapped的value (converted 成了int 以后的值) |
Long | return (int)(value ^ (value >>> 32)); | 由于最后的hashCode的类型是int, 而int只有32位,所以64位的Long值,要砍掉一半。为了不失去一半的信息,这个expression的意思是,会值的高32位和低32位的值进行exclusive OR的结果,这样就保证结果均会受前后32位的影响,不会丢失信息。如果直接把Long转成int, 那就会丢掉高32位的信息,这就不是好的implementation |
Float | return floatToIntBits(value); | 把float 转成bits, 具体的implementation是我不是太懂,大概是把32位的float 直接当成int输出来,不管那些位置信息,例如本来第31位是符号位,第23到30位代表的是指数,但转成int值后,这些值代表的意义都不存在了,仅仅作为普通的int数位。 |
Double | bits = doubleToLongBits(value); return (int)(bits ^ (bits >>> 32)); | 第一段code与 floatToIntBits(value) 一样 第二段code是与Long.hashCode()一样 |
String | s[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方法中考虑的每一个域),完成以下步骤:
4.写完了hashCode方法之后,问自己“是否相等的实例具有相等的散列码”。如果不是的话,找出原因,并修正错误。
例如
public int hashCode()
{
int result =17;
result=result*37 + width;
result=result*37 + height;
return result;
}
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)。
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;
}