首先,jdk1.8在擴容的情況下,將原來的鏈表,根據(jù)resize后的位置拆成了2個鏈表,拆完之后在分別放到2個位置上,所以不會出現(xiàn)成環(huán)的情況。。。
JDK1.7的情況下,當(dāng)hashMap擴容的時候,會調(diào)用transfer方法,重新為鏈表中的數(shù)據(jù)分配鏈表,使得在重新分配的過程中,容易產(chǎn)生環(huán)狀死鎖或者數(shù)據(jù)丟失;
在了解來龍去脈之前,我們先看看HashMap的數(shù)據(jù)結(jié)構(gòu)。
在內(nèi)部,HashMap使用一個Entry數(shù)組保存key、value數(shù)據(jù),當(dāng)一對key、value被加入時,會通過一個hash算法得到數(shù)組的下標(biāo)index,算法很簡單,根據(jù)key的hash值,對數(shù)組的大小取模 hash & (length-1),并把結(jié)果插入數(shù)組該位置,如果該位置上已經(jīng)有元素了,就說明存在hash沖突,這樣會在index位置生成鏈表。
如果存在hash沖突,最慘的情況,就是所有元素都定位到同一個位置,形成一個長長的鏈表,這樣get一個值時,最壞情況需要遍歷所有節(jié)點,性能變成了O(n),所以元素的hash值算法和HashMap的初始化大小很重要。
當(dāng)插入一個新的節(jié)點時,如果不存在相同的key,則會判斷當(dāng)前內(nèi)部元素是否已經(jīng)達到閾值(默認(rèn)是數(shù)組大小的0.75),如果已經(jīng)達到閾值,會對數(shù)組進行擴容,也會對鏈表中的元素進行rehash。
移動的邏輯也很清晰,遍歷原來table中每個位置的鏈表,并對每個元素進行重新hash,在新的newTable找到歸宿,并插入。