最近在重温java源码,一边看一边总结下,并且分享下自己的心得,共同学习,欢迎指点。这一篇说下hashCode和equals的源码中的一些注意点,争取把原理讲透彻:
public native int hashCode();
这是Object中的方法,可以发现是个本地方法。但是许多类都会覆盖这个方法比如String,Integer,Long等基础类。所以不同的类有不同的散列方式,如Integer类只是单纯的返回了value;
public int hashCode() {
return value;
}
public int hashCode() {
int h = hash;
int len = count;
if (h == 0 && len > 0) {
int off = offset;
char val[] = value;
for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}
static inline intptr_t get_next_hash(Thread * Self, oop obj) {
intptr_t value = 0 ;
if (hashCode == 0) {
value = os::random() ;
} else
if (hashCode == 1) {
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 {
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;
}
根据hashCode的不同情况做不同处理,如1的时候返回随机数,2则返回跟地址有关的一个数值。具体逻辑含义需要仔细看下jvm源码。
public boolean equals(Object obj) {
return (this == obj);
}
这是equals的源码,没有特殊,判断地址。
public class MyInt {
public int value ;
MyInt(int value){
this.value=value;
}
public boolean equals(Object o){
if(this == o)
return true;
if(!(o instanceof MyInt))
return false;
MyInt mi = (MyInt)o;
return (this.value == mi.value);
}
}
Map map = new HashMap();
map.put(new MyInt(2), "test");
System.out.println(map.get(new MyInt(2)));
如果你期望返回test那么就错了。你可能以为重写了equals方法,用hashmap就会对应到一个key上。不会的 。hashmap用的是hashcode进行散列的。两个不一样的对象在hashCode看来是不一样的。如果hashMap的hashCode恰巧也相等了,好吧恭喜你,中奖了。
e.hash == hash && ((k = e.key) == key || key.equals(k))