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则直接连接在两个子链表的末尾,也就避免了这个问题。

 

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