Java中的hashCode()是如何实现的?
转载⾃:blog.csdn/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的:
2. 对于各⾃primitive data types的wrapper class,例如Integer, Double, Character等等,它们各⾃的hashCode() implementation也不⼀样,我写了如下的总结:
Java Wrapper Class hashCode() implementation Summary
Wrapper Class hashCode() implementation
java源代码加密Note
Boolean return 1231 or 1237;1231 和 1237 是两个相对较⼤的质数,请看这⾥: stackoverflow/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的va
lue (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? stackoverflow/questions/299304/why-does-javas-
hashcode-in-string-use-31-as-a-multiplier
这个公式保证String⾥的第⼀个character都对最后产⽣的 hashcode 有所影响
[java]
1. int a = 2;
2. System.out.print( "int a = 2.hashCode()= " );
3. System.out.println(a.hashCode());
3. ⾃定义的class, 如果override了equals()⽅法,那么就⼀定要override hashCode()⽅法,具体⽅法请看
Some FAQs:
Q1. 为何hashCode会是int⽽不是long呢?
答:因为在java中,⼀个Array的最⼤长度是: Integer.MAX_VALUE ()
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:
And also this:
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;
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论