java的hashMap擴容新地址計算的巧妙
what:
hashmap擴容
1、重新建立一個新的陣列,長度為原陣列的兩倍(實際長度為2的n次冪);
2、遍歷舊陣列的每個資料,重新計算每個元素在新陣列中的儲存位置(一次性完成);使用節點的hash值與舊陣列長度進行位與運算,如果運算結果為0,表示元素在新陣列中的位置不變;否則,則在新陣列中的位置下標=原位置+原陣列長度。
why:
為什麼擴容時節點重 hash 只可能分佈在原索引位置或者 原索引長度+oldCap 位置呢?換句話說,擴容時使用節點的hash值跟oldCap進行位與運算,以此決定將節點分佈到原索引位置或者原索引+oldCap位置上的原理是什麼呢?
假設老表的容量為16,則新表容量為16*2=32,假設節點1的hash值為 0000 0000 0000 0000 0000 1111 0000 1010,節點2的hash值為 0000 0000 0000 0000 0000 1111 0001 1010。
那麼節點1和節點2在老表的索引位置計算如下圖:
計算1(16個桶的真實計算),由於老表的長度限制,節點1和節點2的索引位置只取決於節點hash值的最後4位。
計算2(32個桶的真實計算,擴容1倍後),計算2為元素在新表中的索引計算,可以看出如果兩個節點在老表的索引位置相同,則新表的索引位置只取決於節點hash值倒數第5位的值,而此位置的值剛好為老表的容量值16,此時節點在新表的索引位置只有兩種情況:原索引位置和 原索引+oldCap(放大1倍)
由於結果只取決於節點hash值的倒數第5位,而此位置的值剛好為老表的容量值16,因此此時新表的索引位置的計算可以替換為計算3,直接使用節點的hash值與老表的容量16進行位於運算,如果結果為0則該節點在新表的索引位置為原索引位置,否則該節點在新表的索引位置為 原索引+ oldCap 位置。