//鍊錶轉紅黑樹的閾值
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...