HashMap的resize()過程簡述版本

初始默認大小爲16,默認負載閾值0.75;每次擴容2倍;

 

1. 如果oldCap已經超出最大容量。

將Integer.MAX_VALUE賦給閾值,返回舊錶;

 

2. 如果oldCap以及oldCap*2是介於16和最大容量之間(多落在這個分支),oldCap*2得到新容量,oldThr*2得到新閾值;

 

3. 如果oldCap==0並且oldThr>0,那麼oldThr直接賦給newCap;

這個比較有意思,涉及到HashMap的幾種初始化,深入說一下。

(1)如果使用public HashMap()初始化表,oldCap爲0,oldThr也爲0,會走到下一個分支(第4點);

(2)如果使用public HashMap(int initialCapacity)初始化,會進一步調用public HashMap(int initialCapacity, float loadFactor),該構造方法將threshold賦值爲大於等於initialCapacity的2的冪,也就出現了第3點的分支(oldCap只跟表有關係,與initialCapacity無關)。

(3)如果落在這個分支,newCap獲得了threshold,在跳出分支之後還有單獨的代碼對threshold賦值,賦值爲newCap*loadFactor。

 

4. 如果oldCap==0並且oldThr==0,那麼newCap賦值16,newThr賦值16*0.75;

 

5. 擴容結束之後,會對錶rehash,樹的部分略過,鏈表的部分就是根據hash高位值劃分爲兩個子鏈表,一個連接在原來的位置,一個連接到j+oldCap的位置。

jdk1.7之前的擴容操作,如果涉及到多線程可能會出現鏈表循環的問題,原因是1.7版本採用遍歷+頭插的方法進行rehash,1.8則直接連接在兩個子鏈表的末尾,也就避免了這個問題。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章