hashmap 的擴容和樹形化

2021-10-02 02:35:42 字數 1886 閱讀 3003

//鍊錶轉紅黑樹的閾值

static

final

int treeify_threshold =8;

//紅黑樹轉鍊錶的閾值

static

final

int untreeify_threshold =6;

/***最小樹形化容量閾值:即 當雜湊表中的容量 > 該值時,才允許樹形化煉表 (即 將鍊錶 轉換成紅黑樹)

*否則,若桶內元素太多時,則直接擴容,而不是樹形化

*為了避免進行擴容、樹形化選擇的衝突,這個值不能小於 4 * treeify_threshold

**/static

final

int min_treeify_capacity =

64;

第乙個和第二個變數沒有什麼問題,關鍵是第三個:是表示只有在陣列長度大於64的時候,才能樹形化列表嗎?

實際上,這兩個變數是應用於不同場景的。

鍊錶長度大於8的時候就會呼叫treeifybin方法轉化為紅黑樹,但是在treeifybin方法內部卻有乙個判斷,當只有陣列長度大於64的時候,才會進行樹形化,否則就只是resize擴容。

為什麼呢?

因為鍊錶過長而陣列過短,會經常發生hash碰撞,這個時候樹形化其實是治標不治本,因為引起鍊錶過長的根本原因是陣列過短。執行樹形化之前,會先檢查陣列長度,如果長度小於 64,則對陣列進行擴容,而不是進行樹形化。

所以發生擴容的時候是在兩種情況下

hashmap內部建立過程

構造器(只是初始化一下引數,也就代表著只有新增資料的時候才會構建陣列和鍊錶)—呼叫put方法—put方法會呼叫resize方法(在陣列為空或者超過閾值的時候,put方法呼叫resize方法)

hashmap是如何擴容的

1.hashmap中閾值threshold的設定

剛開始,閾值設定為空

**如下:

node

oldtab = table;

int oldcap =

(oldtab == null)?0

: oldtab.length;

int oldthr = threshold;

int newcap, newthr =0;

if(oldcap >0)

elseif(

(newcap = oldcap <<1)

< maximum_capacity &&

oldcap >= default_initial_capacity)

newthr = oldthr <<1;

// double threshold

}else

if(oldthr >0)

// initial capacity was placed in threshold

newcap = oldthr;

else

if(newthr ==0)

threshold = newthr;

2.資料轉移

假設擴容前的 table 大小為 2 的 n 次方,元素的 table 索引為其 hash 值的後 n 位確定

擴容後的 table 大小即為 2 的 n+1 次方,則其中元素的 table 索引為其 hash 值的後 n+1 位確定,比原來多了一位

擴容是乙個特別耗效能的操作,所以當程式設計師在使用 hashmap 的時候,估算 map 的大小,初始化的時候給乙個大致的數值,避免 map 進行頻繁的擴容。

hashmap 的容量計算公式 :size/0.75 +1 。

原理就是保證,閾值(陣列長度*0.75)>實際容量

HashMap元素插入和擴容

從jdk1.8開始hashmap的儲存結構變成了陣列 鍊錶 紅黑樹,單鏈表中元素個數超過指定閾值,會轉化為紅黑樹結構儲存 提高查詢效率 從1.7到1.8,在hash衝突的時候,鍊錶的插入將頭插法改為尾插法,防止在高併發的情緒出現迴圈鍊錶 hashmap的預設陣列大小為16,代表hash陣列的長度 預...

HashMap的擴容問題

hashmap的重要特性是它的容量 capacity 負載因子 load factor 和擴容極限 threshold resizing 當hashmap中的元素個數 陣列大小 乘以 load factor 負載因子預設為0.75 時,陣列就會擴容。hashmap擴容是非常消耗效能的操作,預設元素的...

原始碼擴容及HashMap樹化

對於hashmap初始容量為16 負載因子為0.75 最小樹化長度為64 當前鍊錶的長度大於8時進行樹化,轉化為紅黑樹,進入樹化方法則會發現,樹化之前會先進性判斷,陣列的長度如果小於64則會先進行擴容。擴容的方式就是建立新的陣列 陣列長度並不能變 將老元素重新新增到新的陣列中。for int bin...