Java中hashCode()方法以及HashMap()中hash()方法


Java的Object類中有一個hashCode()方法:

public final native Class<?> getClass();  
public native int hashCode();  
public boolean equals(Object obj) {  
  return (this == obj);  
}   
public String toString() {  
 return getClass().getName() + "@" +  Integer.toHexString(hashCode());  
} 
hashCode()是一個native方法,意味着方法的實現和硬件平台有關,默認實現和虛擬機有關,對 於有些JVM,hashCode()返回的就是對象的地址,大多時候JVM根據一定的規則將與對象相關的信息(比如對象的存儲地址,對象的字段等)映射成一個數值,並返回。
例如:HotSpot JVM中生成hash實現:hotspot/src/share/vm/runtime/synchronizer.cpp
 
在Java中,hashCode()方法的主要作用是為了配合基於散列的集合(HashSet、HashMap)一起正常運行。當向集合中插入對象時,調用equals()逐個進行比較,這個方法可行卻效率低下。因此,先比較hashCode再調用equals()會快很多。下面這段代碼是java.util.HashMap的中put方法的具體實現:
public V put(K key, V value) {
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key.hashCode());
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }
 
        modCount++;
        addEntry(hash, key, value, i);
        return null;
    }

 indexFor()源碼如下:

static int indexFor(int h, int length) {  
    return h & (length-1);  
} 

因為hashMap要求Entry數組長度必須為2的冪(hashMap默認值為16,hashTable沒有這個要求,默認值為11),所以上述代碼就是取h的低4位作為Entry數組的下標。由於覆蓋equals()需要覆蓋hashCode(),所以hashCode()有時並不十分完美,比如只和高位有關等等,因此需要再次hash()一下。

hash()方法在JDK1.7中如下:

static int hash(int h) {
    // This function ensures that hashCodes that differ only by
    // constant multiples at each bit position have a bounded
    // number of collisions (approximately 8 at default load factor).
    h ^= (h >>> 20) ^ (h >>> 12);
    return h ^ (h >>> 7) ^ (h >>> 4);
}

這樣設計保證了對象的hashCode的32位值只要有一位發生改變,整個hash()返回值就會改變,高位的變化會反應到低位里。

具體分析參考:http://www.iteye.com/topic/709945

https://www.zhihu.com/question/20733617

hash()方法在JDK1.8中如下:

static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

 這樣設計保證了對象的hashCode的高16位的變化能反應到低16位中,相比較而言減少了過多的位運算,是一種折中的設計。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM