hashCode()是什么
Object的hashCode()通过JVM虚拟机来实现其算法,主要为对象计算出一个hash值,hash值可以先理解为当前对象在内存中存储的相对位置
hashCode()的作用及怎么用:
通过该hash值可以高效的对两个对象进行比较,比较逻辑如下:
if (A.hash != B.hash){
A != B
}else {
if (A.equals != B.equals) {
A != B
} else {
A == B
}
}
辅助理解:
Object的hashCode算法会被很多基础类使用,比如HashMap中计算hash值,但在跟踪jdk 1.8源码时发现hashCode定义是native,所有就需要去扣hashCode源码(Object中hashCode的声明:public native int hashCode();)
在扣源码之前有些朋友误以为默认情况下,hashCode返回的就是对象的存储地址,事实上这种看法是不全面的,确实有些JVM在实现时是直接返回对象的存储地址,但是大多时候并不是这样,只能说可能存储地址有一定关联。下面是HotSpot JVM中生成hash散列值的实现:
static inline intptr_t get_next_hash(Thread * Self, oop obj) {
intptr_t value = 0 ;
if (hashCode == 0) {
// This form uses an unguarded global Park-Miller RNG,
// so it's possible for two threads to race and generate the same RNG.
// On MP system we'll have lots of RW access to a global, so the
// mechanism induces lots of coherency traffic.
value = os::random() ;
} else
if (hashCode == 1) {
// This variation has the property of being stable (idempotent)
// between STW operations. This can be useful in some of the 1-0
// synchronization schemes.
intptr_t addrBits = intptr_t(obj) >> 3 ;
value = addrBits ^ (addrBits >> 5) ^ GVars.stwRandom ;
} else
if (hashCode == 2) {
value = 1 ; // for sensitivity testing
} else
if (hashCode == 3) {
value = ++GVars.hcSequence ;
} else
if (hashCode == 4) {
value = intptr_t(obj) ;
} else {
// Marsaglia's xor-shift scheme with thread-specific state
// This is probably the best overall implementation -- we'll
// likely make this the default in future releases.
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;
}
该实现位于hotspot/src/share/vm/runtime/synchronizer.cpp文件下。如上参考:浅谈Java中的hashcode方法
在有些情况下,程序设计者在设计一个类的时候为需要重写equals方法,比如String类,但是千万要注意,在重写equals方法的同时,必须重写hashCode方法。为什么这么说呢?
主要是Object原生的hash值可以理解为取的是对象地址,如果比较两个String的话,两个对象的地址一定不同,如果不重写hashCode两个对象一定不相同(相同的意思是内容相同,而不是同一个对象),故为了达到时两个对象内容相同的情况下hashCode相关,则需重写Object.hashCode();且保证只要元数据相同,则hashCode必须相同,不相同的元数据hashCode也可以相同
hash主要提供了一种快速查找的手段,但该手段同时会引入冲突问题,如何解决冲突问题的方法则将在后续阐述