2015-10-16 47 views
6

根據this blog entry,HashMap在已經檢索到的哈希碼上重新調用了自己的實現hashCode()(稱爲hash())。HashMap爲什麼以及如何將自己的hashCode()的內部實現稱爲hash()?

如果密鑰不爲空的話,它將調用密鑰對象上散列函數,見線4在上述方法中,即key.hashCode(),所以key.hashCode()返回散列值之後,第4行看起來像

INT哈希散列=(散列值)

,現在,它適用返回散列值到它自己的散列函數。

我們可能想知道爲什麼我們使用散列(hashValue)再次計算散列值。答案是,它防範低質量hash>函數。

Can HashMap 準確重新分配hashcode? HashMap可以存儲對象,但它無法訪問爲其對象分配hashCode的邏輯。例如,hash()不可能的邏輯集成以下hashCode()實現背後:

public class Employee { 
protected long employeeId; 
protected String firstName; 
protected String lastName; 

public int hashCode(){ 
    return (int) employeeId; 
} 

} 
+3

的可能的複製[認識奇怪的Java哈希函數(http://stackoverflow.com/questions/9335169/understanding-strange-java-hash-function) – Nayuki

+1

@NayukiMinase猜猜散列'()的實現'隨着時間的推移已經發生了變化,因爲1.8.0_51版本不同/更簡單(參見我的答案)。 – Andreas

回答

13

hash()導出從實際的散列碼的「改進的」哈希碼,因此相等的輸入將總是等於輸出(從jdk1 .8.0_51):

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

至於爲什麼哈希碼需要改進,讀出的方法的的Javadoc:

單位計算key.hashCode()的d散佈(XORs)散列的較高位以降低。由於該表使用冪級別掩碼,所以只在當前掩碼之上的位上發生變化的散列總是會發生衝突。 (在已知的例子中,Float鍵的集合在小表中保持連續的整數)。因此,我們應用一個變換向下擴展高位的影響。在速度,效用和比特傳播質量之間進行權衡。因爲許多常見的散列集合已經合理分佈(所以不能從擴散中受益),並且因爲我們使用樹來處理箱子中的大量碰撞,所以我們只需以最便宜的方式對一些位移進行異或運算,以減少系統損失,以及合併由於表邊界而不會用於索引計算的最高位的影響。

+2

換言之,'HashMap'類從其對象中獲取原始的'hashCode()'值,並應用一對一的「白化」轉換來嘗試使分佈更均勻。 – Nayuki

+0

@Andreas我接受了解決方案!謝謝。你能聯繫我,或者也許可以解釋一下,兩個掩碼是什麼?谷歌搜索該詞產生無。 – Muno

+1

@Muno兩次掩碼功能是指哈希表大小始終是2的冪(2,4,8,16,32,...),所以要計算散列表存儲桶,簡單的位掩碼操作可以(例如'h&0x1F'爲散列表大小32),這比模數運算('%')快。 – Andreas

相關問題