上文講到HashMap的增加方法,現(xiàn)在繼續(xù) 上文鏈接
HashMap在上一篇源碼分析的文章中赤拒,如果使用put的時候如果元素數(shù)量超過threshold就會調(diào)用resize進(jìn)行擴(kuò)容
1.擴(kuò)容機(jī)制
想要了解HashMap的擴(kuò)容機(jī)制你要有這兩個問題
- 1.什么時候才需要擴(kuò)容
- 2.HashMap的擴(kuò)容是什么
在添加元素的時候如果超過threshold設(shè)置的閥值點(diǎn)就會進(jìn)行擴(kuò)容狠角,簡單的來說就是一個水壺容量是二升吕粹,然后這個時候已經(jīng)滿了但是你還要繼續(xù)加水存淫,咋辦幔烛?換個大的。所以HashMap的擴(kuò)容就和你這個水壺一樣,水已經(jīng)滿了那我就在換個大的水壺繼續(xù)加水抖拦。不過在你換水壺的時候是有很多條件的。
在我看這個resize的源碼的時候我也是一臉懵逼舷暮,最后請教了大佬得到的回答是因?yàn)?.8加入了紅黑樹比較麻煩可以看一下1.7的态罪,然后我有去網(wǎng)上看了一下別人寫的文章基本上都是基于1.7的resize。所以這里就看1.7的resize來分析脚牍。
來看JDK1.7中resize的實(shí)現(xiàn)向臀。
復(fù)制操作是調(diào)用的transfer方法
在1.7中的resize結(jié)合一下我們的小例子可以這樣理解,去超市買一個大一點(diǎn)的水壺诸狭,然后把以前水壺里面的水給倒進(jìn)新的水壺里面券膀。再把我們當(dāng)前的水壺的容量替換掉,告訴別人我的容量更大了驯遇。(強(qiáng)行比喻哈哈哈哈哈)
1.7中的resize就是這么簡單芹彬,那我們在看一下1.8中的resize(),這樣再看就不會一臉懵逼了
我在這里把1.8的resize方法分為兩部分
- 1.計算新的newCap(新的容量)和newThr(新閥值點(diǎn))
- 2.復(fù)制新的數(shù)組
第一部分
第二部分
對比一下1.7
- 1.7元素不需要更換位置。1.8元素的位置要么是在原位置叉庐,要么是在原位置再移動2次冪的位置
- 不需要像1.7一樣重新計算hash
2.刪除
刪除的話就是首先先找到元素的位置舒帮,如果是鏈表就遍歷鏈表找到元素之后刪除。如果是用紅黑樹就遍歷樹然后找到之后做刪除陡叠,樹小于6的時候要轉(zhuǎn)鏈表玩郊。
刪除方法:
調(diào)用removeNode:
3.查找元素
查找方法,通過元素的Key找到Value枉阵。
調(diào)用getNode()方法
看完可以知道邏輯是先通過Key計算出索引的位置译红,然后先檢查第一個節(jié)點(diǎn)看看是否是我們要的節(jié)點(diǎn),如果不是在去查看是否死紅黑樹和鏈表兴溜。
4.遍歷
我們通過下面幾個例子來演示一下HashMap怎么遍歷
1.分別遍歷Key和Values
for (String key:map.keySet()){
System.out.println(key);
}
for (Object value : map.values()) {
System.out.println(value);
}
2.迭代
Iterator<Map.Entry<String, Object>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, Object> mapEntry = iterator.next();
System.out.println(mapEntry.getKey() + "====" + mapEntry.getValue());
}
3.獲取 key 集合
Set<String> keySet = map.keySet();
for (String str : keySet) {
System.out.println(str + "====" + map.get(str));
}
4.獲取Entry 集合侦厚,遍歷Entry 集合
Set<Map.Entry<String, Object>> entrySet = map.entrySet();
for (Map.Entry<String, Object> entry : entrySet) {
System.out.println(entry.getKey() + "====" + entry.getValue());
}
對比來說使用迭代的方式是最好的,也可以在迭代的時候?qū)系脑剡M(jìn)行刪除
總結(jié)
基于JDK1.8的HashMap是由數(shù)組+鏈表+紅黑樹組成拙徽,當(dāng)鏈表長度超過 8 時會自動轉(zhuǎn)換成紅黑樹刨沦,當(dāng)紅黑樹節(jié)點(diǎn)個數(shù)小于 6 時,又會轉(zhuǎn)化成鏈表膘怕。相對于早期版本的 JDK HashMap 實(shí)現(xiàn)想诅,新增了紅黑樹作為底層數(shù)據(jù)結(jié)構(gòu),在數(shù)據(jù)量較大且哈希碰撞較多時,能夠極大的增加檢索的效率侧蘸。HashMap并不是線程安全的裁眯,支持K和V為null ,k重復(fù)會覆蓋,V可以重復(fù)讳癌,還有一點(diǎn)HashMap遍歷的數(shù)據(jù)不是有序的是無序的