【JDK源码学习】HaspMap扩容操作

HashMap的扩容是学习HashMap源码的重中之重,面试中经常被问到。本文就以实例的方式,解析HashMap的扩容过程,以及JDK1.8和1.7的扩容操作的区别

一、什么时候HashMap会扩容

调用HashMap的put方法时,如果当前的数组(HashMap的底层数据结构就是数组)为null,或者数组的长度大于阈值(数组长度*负载因子)时,会发生扩容。数组为null时,会扩容成默认长度或指定长度;数组超过阈值时,会扩容成原数组的两倍。

二、怎么扩容

假设现在有一个HashMap,长度为5,往里面put了三个元素put(1, val1),put(6, val2),put(11, val3),如图:

【JDK源码学习】HaspMap扩容操作_第1张图片

扩容:

新数组的容量会扩大一倍,里面暂时没有元素,新数组示意图如下:

JDK1.7 元素位置计算

第一步:遍历到oldTab[1]的(11,val3)这个元素,算出应该放在新newTab[1],完成后结构如下:

【JDK源码学习】HaspMap扩容操作_第2张图片

第二步,遍历到oldTab[1]的(6,val2)元素,计算出应该放在newTab[6]的位置,完成后结构如下:

【JDK源码学习】HaspMap扩容操作_第3张图片

第三步,遍历到oldTab[1]的(1,val1)元素,计算出应该放在newTab[1]的位置,由于index=1的位置上,已经有一个元素了,

所以(1,val1)元素,将放在newTab[1]的链表头上,完成后的结构如下:

【JDK源码学习】HaspMap扩容操作_第4张图片

完成元素的位置计算,扩容也完成了。从图中可以看出,扩容后原tab[1]处的链表,头尾发生了交换。

JDK1.8 元素位置计算

这个就骚气了

第一步:遍历到oldTab[1]的(11,val3)这个元素,算出应该放在新newTab[1],发现index还是1,没有发生改变,loHead、LoTail会指向这个元素,newTab暂时没有发生变化

【JDK源码学习】HaspMap扩容操作_第5张图片

第二步,遍历到oldTab[1]的(6,val2)元素,计算出应该放在newTab[6]的位置,index发生了变化,hiHead、hiTail会指向这个元素,newTab还是没有变化。

【JDK源码学习】HaspMap扩容操作_第6张图片

第三步,遍历到oldTab[1]的(1,val1)元素,计算出应该放在newTab[1]的位置,发现index还是1,没有发生改变。这时,由于loHead、loTail已经不为null了(指向元素(11,val3)),会将loTail.next指向(1,val1),loTail也指向(1,val1),如图:

if (loTail == null)
    loHead = e;
else
    loTail.next = e;
loTail = e;

【JDK源码学习】HaspMap扩容操作_第7张图片

第四步,将oldTab[1]处理结束后,将loHead、loTail、hiHead、hiTail,挂到newTab执行的index上去。

源码中的处理如下,只需把loHead、hiHead放到正确的位置即可。其中loHead链表index没发生改变,然后放在newTab[1]上,hiHead发生了改变,应该放在j + oldCap位置上,例子中j=1,oldCap=5。:

if (loTail != null) {
    loTail.next = null;
    newTab[j] = loHead;
}
if (hiTail != null) {
    hiTail.next = null;
    newTab[j + oldCap] = hiHead;
}

【JDK源码学习】HaspMap扩容操作_第8张图片

完成元素的位置计算,扩容也完成了。从图中可以看出,扩容后原tab[1]处的链表,头尾保持了1在11的后面。这就是jdk1.8与1.7的区别之处。

补充:

1、jdk1.8中是如果判断元素应该存放的index,在扩容之后,是否应该发生改变?上源码

【JDK源码学习】HaspMap扩容操作_第9张图片

判断原来的 hash 值与oldTab容量按位与操作是 0 或 1 就行,0 的话索引就不变,1 的话索引变成原索引加上扩容前数组

2、扩容后,如果index发生了改变,应该放在newTab的哪个位置呢,上源码:

【JDK源码学习】HaspMap扩容操作_第10张图片

其中loHead是index不变的链表,还是放在原来的位置j上,hiHead是index发生变化的链表,放在了j+oldCap上。

 

你可能感兴趣的:(JAVA)