從jdk1.8開始hashmap的儲存結構變成了陣列+鍊錶+紅黑樹,單鏈表中元素個數超過指定閾值,會轉化為紅黑樹結構儲存(提高查詢效率);
從1.7到1.8,在hash衝突的時候,鍊錶的插入將頭插法改為尾插法,防止在高併發的情緒出現迴圈鍊錶;
hashmap的預設陣列大小為16,代表hash陣列的長度;
預設的載入因子是0.75,代表存入元素大於陣列大小*載入因子就進行擴容;
hashmap是執行緒不安全的,方法都未使用synchronized關鍵字;
允許key和value值為null(預設hash演算法的情況下,放在資料的0號位置);
//預設初始大小:16
static
final
int default_initial_capacity =
1<<4;
//最大容量:2^30
static
final
int maximum_capacity =
1<<30;
//預設的記載因子:0.75
static
final
float default_load_factor =
0.75f
;//鍊錶的長度大於8,就需要將對應的鍊錶轉為紅黑樹
static
final
int treeify_threshold =8;
//紅黑樹的節點數小於6,就需要將其轉為鍊錶
static
final
int untreeify_threshold =6;
//將鍊錶轉為紅黑樹的另乙個前提條件,總元素樹大於64
static
final
int min_treeify_capacity =
64;
static
final
inthash
(object key)
public v put
(k key, v value)
final v putval
(int hash, k key, v value,
boolean onlyifabsent,
boolean evict)
if(e.hash == hash &&
((k = e.key)
== key ||
(key != null && key.
equals
(k))))
//掃瞄發現,鍊錶中存在key一致的元素,結束迴圈
break
; p = e;}}
if(e != null)
}++modcount;if(
++size > threshold)
//新增之後,元素個數是否大於閾值,進行擴容
resize()
;afternodeinsertion
(evict)
;return null;
}
final node
resize()
elseif(
(newcap = oldcap <<1)
< maximum_capacity &&
oldcap >= default_initial_capacity)
//長度沒有超過maximum_capacity,陣列長度擴容一倍
newthr = oldthr <<1;
// 新增閾值,擴容一倍
}else
if(oldthr >0)
// 陣列為空,指定了新增閾值
newcap = oldthr;
else
if(newthr ==0)
threshold = newthr;
//擴容後的新增閾值
@suppresswarnings()
node
newtab =
(node
)new
node
[newcap]
;//擴容之後的陣列
table = newtab;
if(oldtab != null)
else
}while
((e = next)
!= null);if
(lotail != null)
if(hitail != null)}}
}}return newtab;
}
首次插入資料,初始化陣列
未指定大小
1.通過無參構造建立
hashmap
map =
newhashmap
<
>()
;
2.put()方法中新增元素,發現table==null,呼叫resize()初始化陣列
if
((tab = table)
== null ||
(n = tab.length)==0
) n =
(tab =
resize()
).length;
3.resiz()方法分支
int oldcap =
(oldtab == null)?0
: oldtab.length;
//初始化,為0
int oldthr = threshold;
//初始化,為0
//執行的分支**
// 陣列為空,未指定了新增閾值,採用預設的數值,16*0.75=12
newcap = default_initial_capacity;
newthr =
(int
)(default_load_factor * default_initial_capacity)
;threshold = newthr;
//擴容後的新增閾值
@suppresswarnings()
node
newtab =
(node
)new
node
[newcap]
;//擴容之後的陣列
table = newtab;
return newtab;
指定了初始化大小
1.通過有參構造建立
hashmap
hashmap =
newhashmap
<
>(7
);//指定初始化大小
2.put()方法中新增元素,發現table==null,呼叫resize()初始化陣列
if
((tab = table)
== null ||
(n = tab.length)==0
) n =
(tab =
resize()
).length;
3.resiz()方法分支
int oldcap =
(oldtab == null)?0
: oldtab.length;
//初始化,為0
int oldthr = threshold;
//初始化,為大於指定大小的最小2次冪
int newcap, newthr =0;
// 陣列為空,指定了新增閾值
newcap = oldthr;
if(newthr ==0)
threshold = newthr;
//擴容後的新增閾值
@suppresswarnings()
node
newtab =
(node
)new
node
[newcap]
;//擴容之後的陣列
table = newtab;
return newtab;
非首次插入擴容
hashMap擴容機制
擴容時空間大小變化 hashmap中,雜湊桶陣列table的長度length大小必須為2的n次方 一定是合數 這是一種非常規的設計,常規的設計是把桶的大小設計為素數。相對來說素數導致衝突的概率要小於合數,具體證明可以參考 hashtable初始化桶大小為11,就是桶大小設計為素數的應用 hashta...
HashMap擴容機制
當map元素容量超過設定的閾值threshold capacity loadfactor時進行擴容,如下圖所示 原理 建立更大容量的新陣列,重新計算每個元素在新陣列中的位置進行遷移。缺點 每個元素需要重新計算hash 鍊錶中元素順序每次遷移後被倒置 原理 在擴充hashmap的時候,不需要像jdk1...
HashMap擴容閾值
閾值 容量 x 負載因子,假設當前hashmap的容量是 16,負載因子是預設值 0.75,那麼當 size 到達16 x 0.75 12 的時候,就會觸發擴容。ps 初始化時,若指定的初始大小不是按照要求來的 則取數字最近的符合規則的數字 將傳過來的引數值轉換為最接近 且大於等於指定引數的 2 的...