學習筆記 | HashMap的底層原理

01 HashMap的底層原理

  • HashMap是一個用於存儲Key-Value鍵值對的集合,每一個鍵值對也叫做Entry
  • 這些個鍵值對(Entry)分散存儲在一個數組當中,這個數組就是HashMap的主幹。
  • HashMap數組每一個元素的初始值都是Null
    在這裏插入圖片描述

對於HashMap,我們最常使用的是兩個方法:Get 和 Put。

1. Put方法的原理
  • 我們需要利用一個哈希函數來確定Entry的插入位置(index)。
    在這裏插入圖片描述
  • 但是,因爲HashMap的長度是有限的,當插入的Entry越來越多時,再完美的Hash函數也難免會出現index衝突的情況。
  • 我們可以利用鏈表來解決。
  • HashMap數組的每一個元素不止是一個Entry對象,也是一個鏈表的頭節點。每一個Entry對象通過Next指針指向它的下一個Entry節點。當新來的Entry映射到衝突的數組位置時,只需要插入到對應的鏈表即可:
  • 新來的Entry節點插入鏈表時,使用的是“頭插法”。是因爲HashMap的發明者認爲,後插入的Entry被查找的可能性更大。
    在這裏插入圖片描述
2.Get方法的原理
  • 使用Get方法根據Key來查找Value的時候,發生了什麼呢?
  • 首先會把輸入的Key做一次Hash映射,得到對應的index
  • 由於剛纔所說的Hash衝突,同一個位置有可能匹配到多個Entry,這時候就需要順着對應鏈表的頭節點,一個一個向下來查找。

Q:HashMap默認的初始長度是多少?爲什麼這麼規定?
  • HashMap的默認初始長度是16,並且每次自動擴展或是手動初始化時,長度必須是2的冪。
  • 之所以選擇16,是爲了服務於從Key映射到indexHash算法。
Q:如何實現一個儘量均勻分佈的Hash函數呢?
  • 我們通過利用Key的HashCode值來做某種運算。
    在這裏插入圖片描述
Q:高併發情況下,爲什麼HashMap可能會出現死鎖?
  • RehashHashMap在擴容的時候的一個步驟。
  • HashMap的容量是有限的。當經過多次元素插入,使得HashMap達到一定飽和度時,Key映射位置發生衝突的機率會逐漸提高。
  • 這時候,HashMap需要擴展它的長度,也就是進行Resize。

影響發生Resize的因素有兩個:

  1. Capacity
    HashMap的當前長度。HashMap的長度是2的冪。
  2. LoadFactor
    HashMap負載因子,默認值爲0.75f

衡量HashMap是否進行Resize的條件如下:

  • HashMap.Size >= Capacity * LoadFactor

Resize步驟

  1. 擴容
    創建一個新的Entry空數組,長度是原數組的2倍。
  2. ReHash
    遍歷原Entry數組,把所有的Entry重新Hash到新數組。爲什麼要重新Hash呢?因爲長度擴大以後,Hash的規則也隨之改變。
  • ReHash在併發的情況下可能會形成鏈表環。 從而導致死鎖。
Q:在Java8中,HashMap的結構有什麼優化?
  • ConcurrentHashMap這個集合類兼顧了線程安全和性能。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章