浅谈 HashMap 的扩容过程和 put 过程

这是在基于 JDK 1.8 之后的源码进行的浅谈

简介:

在 JDK 8 中,HashMap 由 “数组 + 链表 + 红黑树” 组成。链表过长会影响查询性能,而红黑树搜索的时间复杂度是 O(logn),而链表则是O(n),JDK 8 对数据结构进行了进一步的优化,引入了红黑树,链表在一定条件下会转化为红黑树:

  • 当链表长度超过 8 且数据总量超过 64 时会转红黑树。
  • 将链表转换成红黑树前会判断,如果当前数组的长度小于 64,那么会选择先进行数组扩容,而不是转换为红黑树,以减少搜索时间。

JDK 8 中 HashMap 的结构如下:
在这里插入图片描述

在 HashMap 进行 put 操作的时候,简要流程如下:

  1. 首先根据 key 的值计算 hash 值,找到该元素在数组中存储的下标
  2. 如果数组是空的,则调用 resize 进行初始化
  3. 如果没有发生 hash 冲突则直接将 key 放在数组对应的位置
  4. 如果发生了 hash 冲突,且 key 已经存在,则用新 value 覆盖掉旧值
  5. 如果发生冲突后,发现该节点是红黑树,则直接将该节点挂载在树上
  6. 如果发生冲突,并且该位置是链表,首先判断链表长度是否大于8,如果大于8并且数组容量小于 64 则进行数组扩容;如果链表节点长度大于 8 并且容量大于 64 则将该位置的结构转换为红黑树;否则连败哦插入键值对,若 key 存在,就覆盖掉 value

贴一个高频引用的图,具体流程如下
在这里插入图片描述

扩容时数据的迁移:

在数组元素小于 64 的时候,如果某一位置链表的长度恰好为8,并且要插入的数据恰巧也落在这个位置,那么就会发生数组的扩容。

数组的长度扩容(默认为原来的二倍)不需要重新计算下标,只需要将 hash 值和旧数组长度相与即可确定位置。

由于数组的容量是以2的幂次方扩容的,那么一个Entity在扩容时,新的位置要么在原位置,要么在原长度+原位置的位置,原因如下图
在这里插入图片描述

数组长度变为原来的2倍,表现在二进制上就是多了一个高位参与数组下标确定。此时,一个元素通过hash转换坐标的方法计算后,恰好出现一个现象:最高位是0则坐标不变,最高位是1则坐标变为 “10000+原坐标”,即 “原长度+原坐标”

今天的小八股就到这里啦

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我只有一岁半

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值