hashmap的put操作:
根據key經過擾動函式(異或和取餘的操作)得到乙個hash值,然後根據這個hash進行hash&(n-1)得到乙個索引值,然後判斷當前索引值的陣列位置是否有有元素,如果有元素,再根據equals判斷連個元素是否相同,相同的話,則直接覆蓋當前元素,不相同的話,則產生hash衝突,採用拉鍊法解決衝突。
hashmap1.7
底層結構:陣列+鍊錶。
擴容操作:
void
transfer
(entry[
] newtable,
boolean rehash)
int i =
indexfor
(e.hash, newcapacity)
; e.next = newtable[i]
; newtable[i]
= e;
e = next;}}
}
可以看到在陣列之間的遷移過程中,鍊錶是以頭插法進行遷移的,所以遷移到新陣列後,鍊錶的元素位置會調換,這也是jdk1.7hashmap在多執行緒下會產生死迴圈的原因。
hashmap1.8
底層結構:陣列+鍊錶+紅黑樹
擴容操作:
if
(oldtab != null)
// 9.2 如果e的hash值與老表的容量進行與運算為1,則擴容後的索引位置為:老表的索引位置+oldcap
else
}while
((e = next)
!= null)
;// 10.如果lotail不為空(說明老表的資料有分布到新表上「原索引位置」的節點),則將最後乙個節點
// 的next設為空,並將新表上索引位置為「原索引位置」的節點設定為對應的頭節點
if(lotail != null)
// 11.如果hitail不為空(說明老表的資料有分布到新表上「原索引+oldcap位置」的節點),則將最後
// 乙個節點的next設為空,並將新表上索引位置為「原索引+oldcap」的節點設定為對應的頭節點
if(hitail != null)}}
}}// 12.返回新錶
return newtab;
在jdk1.8的擴容中,通過4個鍊錶節點lohead,lotail,hihead,hitail,即高位鍊錶和低位鍊錶的頭尾節點,先遍歷整個鍊錶,通過hash&n,得到的值要麼是0,要麼是16,為0的即為低位煉表裡的節點,為16即為高位煉表裡的節點,最後將尾結點的next置為null,即分成了高位鍊錶和低位鍊錶,低位鍊錶放在新陣列的原來位置,高位鍊錶放在新陣列的原來位置加上原陣列大小,這樣jdk1.8的擴容操作提高了查詢效率,又解決了多執行緒下死迴圈的問題。 HashMap 1 7和1 8的區別
底層資料結構不一樣,1.7是陣列 鍊錶,1.8則是陣列 鍊錶 紅黑樹結構 當鍊表長度大於8,轉為紅黑樹 jdk1.7用的是頭插法,而jdk1.8及之後使用的都是尾插法,那麼他們為什麼要這樣做呢?因為jdk1.7是用單鏈表進行的縱向延伸,當採用頭插法時會容易出現逆序且環形鍊錶死迴圈問題。但是在jdk1...
HashMap 1 7 原始碼講解
1 hashseed 用於鍵的雜湊碼計算上,用於減少雜湊衝突。通過下面所述的inithashseedasneeded方法來進行初始化 2 threshold 表示可以存放的最大量,它的值為loadfactory 陣列容量,但是存在最大值為1 30 1 即2 30 1 3 loadfactory 負載...
HashMap底層(1 7和1 8)的儲存原理
首先說一下jdk1.7版本的存放原理 當例項化後,底層會直接建立乙個長度為16的一維陣列entry table 然後,說一下新增元素時,呼叫put方法 三種情況儲存 方式一 底層根據key計算hash值,計算出索引位置,檢視當前位置是否有值,如果沒有值,直接存放。情況二 當計算出的索引位置,有值時 ...