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
數據插入的時候大致流程如下:
對數據進行
Hash
值計算。將數據插入前先查看下當前
table
的狀態,如果table
是空需要調用resize
來進行初始化。通過位運算獲得
key
的目標位置。並判斷當前位置情況。如果當前位置為空則直接進行放置,如果跟當前key一直則進行覆蓋。
如果當前有數據則看當前數據類型是否是紅黑樹,是的話需要調用
putTreeVal
。否則就認為是個鏈表,然后循環的查找進行尾部==插入==。同時還要考慮當前鏈表轉紅黑樹。
get
獲得key的hash然后根據hash和key按照插入時候的思路去查找
get
。如果數組位置為NULL則直接返回 NULL。
如果數組位置不為NULL則先直接看數組位置是否符合。
如果數組位置有類型說紅黑樹類型,則按照紅黑樹類型查找返回。
如果數組有next,則按照遍歷鏈表的方式查找返回。
remove
查看是否存在,然后是否在首節點上,是否在紅黑樹上,是否在鏈表上。