【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),如图:

扩容:

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

JDK1.7 元素位置计算

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

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

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

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

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

JDK1.8 元素位置计算

这个就骚气了

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

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

第三步,遍历到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;

第四步,将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;
}

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

补充:

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

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

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

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

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值