hashCode作用
当在集合中判断是否存在(包含)某元素时,可以使用equals方法实现。但如果元素过多,使用equals方法判断则会带来性能问题。
一种有效的方式是比较哈希码(hashCode),这样就可以将一个元素用一个整数来代替。以HashMap为例,其实现流程如下:
(1) 添加一个元素时,使用其哈希码计算内部数组的索引(即所谓的桶)
(2) 如果不相等元素有相同的哈希码,那么他们在同一个桶上并且捆绑在一起,如通过列表处理哈希冲突。
(3) 当进行contains操作时,使用带查找元素的哈希码计算出桶值(索引值),如果对应索引值不存在元素,则直接返回,否则对实例进行equals比较。
使用这种方式,可以大大减少equals的执行次数。
相等的元素一定具有有相同的哈希值。其逆反命题是:哈希码不同,则对应的元素一定不同。
所以,在重写equals方法时,一定要重写hashCode方法。
hashCode 使用准则
hashCode通用约定:
(1) 调用运行Java应用程序中的同一对象,hashCode方法必须始终返回相同的整数。这个整数不需要在不同的Java应用程序中保持一致。
(2) 根据equals(Object)的方法,如果两个对象是相等的,两个对象调用hashCode方法必须产生相同的结果。
(3) 根据equals(Object)的方法,如果两个对象是不相等的,那么两个对象调用hashCode方法并不一定产生不同的整数的结果。
Object的hashCode方法是一个native方法,注释中描述hashCode返回的是由对象存储地址转化得到的值。
public native int hashCode();
这里记录Java源码(Java 8)实现:
static inline intptr_t get_next_hash(Thread * Self, oop obj) {
intptr_t value = 0 ;
if (hashCode == 0) {
// 根据Park-Miller伪随机数生成器生成的随机数
value = os::random() ;
} else if (hashCode == 1) {
// 此类方案将对象的内存地址,做移位运算后与一个随机数进行异或得到结果
intptr_t addrBits = cast_from_oop<intptr_t>(obj) >> 3 ;
value = addrBits ^ (addrBits >> 5) ^ GVars.stwRandom ;
} else if (hashCode == 2) {
value = 1 ; // 返回固定的1
} else if (hashCode == 3) {
value = ++GVars.hcSequence ; // 返回一个自增序列的当前值
} else if (hashCode == 4) {
value = cast_from_oop<intptr_t>(obj) ; // 对象地址
} else {
// 通过和当前线程有关的一个随机数+三个确定值
unsigned t = Self->_hashStateX ;
t ^= (t << 11) ;
Self->_hashStateX = Self->_hashStateY ;
Self->_hashStateY = Self->_hashStateZ ;
Self->_hashStateZ = Self->_hashStateW ;
unsigned v = Self->_hashStateW ;
v = (v ^ (v >> 19)) ^ (t ^ (t >> 8)) ;
Self->_hashStateW = v ;
value = v ;
}
value &= markOopDesc::hash_mask;
if (value == 0) value = 0xBAD ;
assert (value != markOopDesc::no_hash, "invariant") ;
TEVENT (hashCode: GENERATE) ;
return value;
}
String中重写hashCode实现如下:
/* The hash code for a
* {@code String} object is computed as
* <blockquote><pre>
* s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
*/
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
hash = h = isLatin1() ? StringLatin1.hashCode(value)
: StringUTF16.hashCode(value);
}
return h;
}
参考
https://github.com/JetBrains/jdk8u_hotspot/blob/master/src/share/vm/runtime/synchronizer.cpp#L560 hashCode实现
https://blog.csdn.net/changrj6/article/details/100043822 Java Object.hashCode()源码分析
https://www.sitepoint.com/how-to-implement-javas-hashcode-correctly/ hashCode
http://www.codeceo.com/article/java-hashcode-implement.html 如何正确实现Java中的hashCode方法
原创不易,如果本文对您有帮助,欢迎关注我,谢谢 ~_~