1. 程式人生 > >淺析Java中HashMap的底層原理

淺析Java中HashMap的底層原理

什麼是HashMap

HashMap是一個用來儲存鍵值對的資料結構,每一個鍵值對也叫做Entry,這些鍵值對(Entry)分散儲存在一個數組當中,HashMap的每個元素初始值都為null
對於HashMap我們有兩種常用的方法Put和Get, 宣告方式: HashMap map=new HashMap()。
HashMap的預設長度是16並且每次自動擴充套件或者手動擴充套件時長度必須為2
的冪。具體請看下面關於HashCode的介紹。**

  • Put方法
    對於Put方法,比如呼叫map.put(“apple”,0),插入一個key為”apple”的value為0的元素,這個時候需要一個index來確定它在HashMap中的索引位置,但是HashMap的長度是有限的,當插入的Entry越來越多時,會發生index衝突的情況,這個時候我們該怎麼辦呢?其實在HashMap中每一個元素不止

    是一個Entry物件,也是一個連結串列的頭結點,每一個Entry物件都會有一個next指標指向它的下一個Entry物件,當新來的Entry發生對映衝突時,只需要插入相應的連結串列即可。

  • Get方法
    我們使用Get方法來根據輸入的Key來查詢Value會發生什麼呢?
    首先我們會將輸入的Key來做一次Hash對映來得到相應的index,由於剛才所說的Hash衝突,一個index可能對應多個Entry物件,這個時候就要順著相應的Entry頭結點一個一個向下來找。

  • 和HashTable的區別
    ①HashTable是一個執行緒安全的Map實現,但是HashMap是不安全的實現,所以HashMap的效能要高於HashTable,但是如果在高併發的情況下,HashTable實現類會更好一點。
    ②HashTable不允許用null

    值來作為key,value。如果試圖把null值來作為元素放入HashTable中會引發NullPointerException異常;但是null可以在HashMap中被支援。

    關於HashCode

    上面提到根據key的值來計算Entry在HashMap中索引位置,這個過程稱為一次Hash對映,index=Hash(“element”),那麼如何實現一個儘量分佈均勻的Hash函式呢,我們利用Key的HashCode來進行某種運算,為了實現高效的Hash演算法,HashMap的發明者採用了位運算的方式。
    index=HashCode(Key)&(Length-1) ,舉個例子,假定book的HashCode結果為十進位制的3029737,對應的二進位制為1011100011101011101001

    ,再假定HashMap的長度Length為預設的16,Length-1的值為15,對應的的二進位制為1111,1011100011101011101001,1111&1011100011101011101001=1001,十進位制是9,所以index=9。可以說Hash演算法得到的index完全取決於Key的HashCode的後幾位。
    為什麼長度必須為2的冪呢,假定HashMap的長度為10,10-1得到的Length長度為9,對應的二進位制為1001,1001&1011100011101011101001,計算出來的結果為1001,雖然還是9,但是我們換個HashCode試試,對於1011100011101011101111來說,運算結果為1001,index的值還是9,當HashMap長度不為2的冪的時候,有的index出現的機率更大,而有的index則永遠不會出現比如(0111),這顯然違背了Hash演算法均勻分佈的原則,反觀長度為2的冪的時候,最後的HashCode的二進位制位全為1,index等同於HashCode後幾位的值,只要輸入的HashCode本身分佈均勻,那麼Hash演算法的結果就是均勻的。