2016-03-19 49 views
5

我分析了Java中的HashMap源代碼,並獲得有關put方法的問題。爲什麼HashMap.put都會比較哈希和測試是否相等?

下面是put方法在JDK1.6:

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; 
} 

我弄不清楚的if (e.hash == hash && ((k = e.key) == key || key.equals(k)))

爲什麼是這樣的情況?

因爲Java中的超類Object,存在的hashCodeequals一個contract

如果兩個對象是根據equals等於(Object)方法,則調用每個兩者的hashCode方法對象必須產生相同的整數結果。

所以key.equals(k)意味着key.hashCode() == k.hashCode()

hash()低於:

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); 
} 

從而key.hashCode() == k.hashCode()意味着e.hash == hash

那麼爲什麼不是像if ((k = e.key) == key || key.equals(k))那樣的條件?

回答

6

它只是避免方法調用時,它可以:如果哈希(這是不是hashCode(),這是地圖本身的哈希)是從進入的哈希不同,它知道它不必調用equals在所有。只是優化一下。

6

這只是一個優化:比較兩個整數比調用equals()快。

如果這兩個哈希碼不同,那麼根據合同equalshashCode,該地圖知道現有密鑰不等於給定密鑰,並且可以更快地進入下一個密鑰。

1

'hash'變量的值可能與keys hashcode不同。 'hash'變量是調用'hash(key.hashCode())'方法的結果。因此需要比較散列值和密鑰的相等性。