HashMap詳解


主要參考

https://blog.csdn.net/weixin_39900608/article/details/111214986

Hash值

先獲得key對應的hash值。

將該數據的hash值A 與 將A右無符號移動16位后的數值再做^得到最終值。

這個操作叫擾動,原因是怕低幾位出現想同的概率太大,盡可能的將數據實現均勻分布

HashMap的數據結構

JDK1.7:數組+鏈表

JDK1.8:數組+鏈表+紅黑樹

HashMap如何擴容

默認的負載因子(0.75)

初始情況下,當存儲的所有節點數 > (16 * 0.75 = 12 )時,就會觸發擴容

默認負載因子(0.75)在時間和空間成本上提供了很好的折衷。較高的值會降低空間開銷,但提高查找成本(體現在大多數的HashMap類的操作,包括get和put)。設置初始大小時,應該考慮預計的entry數在map及其負載系數,並且盡量減少rehash操作的次數。如果初始容量大於最大條目數除以負載因子,rehash操作將不會發生。

HashMap中鏈表跟紅黑樹切換思路,HashMap中鏈表跟紅黑樹是怎么個維持方法

這個值表示當某個箱子(數組的某個item)中,鏈表長度 >= 8 時,有可能會轉化成樹。設置為8,是系統根據泊松分布的數據分布圖來設定的

在哈希表擴容時,如果發現鏈表長度 <= 6,則會由樹重新退化為鏈表。設置為6猜測是因為時間和空間的權衡

鏈表轉變成樹之前,還會有一次判斷,只有數組長度大於 64 才會發生轉換。這是為了避免在哈希表建立初期,多個鍵值對恰好被放入了同一個鏈表中而導致不必要的轉化

HashMap的鏈表數組。無論我們初始化時候是否傳參,它在自擴容時總是2的次冪

HashMap線程不安全,如何替換

多線程情況下該類安全,可以考慮用HashTable(加了synchronized ),或者CurrentHashMap(自旋鎖cas)

HashMap中的put,get,remove大致過程

put

數據插入的時候大致流程如下:

  1. 對數據進行Hash值計算。

  2. 將數據插入前先查看下當前table的狀態,如果table是空需要調用resize來進行初始化。

  3. 通過位運算獲得key的目標位置。並判斷當前位置情況。

  4. 如果當前位置為空則直接進行放置,如果跟當前key一直則進行覆蓋。

  5. 如果當前有數據則看當前數據類型是否是紅黑樹,是的話需要調用putTreeVal

  6. 否則就認為是個鏈表,然后循環的查找進行尾部==插入==。同時還要考慮當前鏈表轉紅黑樹。

get

  1. 獲得key的hash然后根據hash和key按照插入時候的思路去查找get

  2. 如果數組位置為NULL則直接返回 NULL。

  3. 如果數組位置不為NULL則先直接看數組位置是否符合。

  4. 如果數組位置有類型說紅黑樹類型,則按照紅黑樹類型查找返回。

  5. 如果數組有next,則按照遍歷鏈表的方式查找返回。

remove

查看是否存在,然后是否在首節點上,是否在紅黑樹上,是否在鏈表上。

這幾種情況,找到了則直接刪除,同時注意平衡性


免責聲明!

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



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