【Java】一篇详解HashMap的扩容机制!!

如果小伙伴对HashMap的扩容机制不了解,那么这篇文章带你吃透扩容机制,如果对你有帮助,希望可以点赞、收藏!!

HashMap的扩容机制是为了应对元素数量增长导致的哈希冲突加剧问题,通过扩大数组容量来分散元素,保证查询效率。
核心逻辑是:当数组数量超过阈值时,将数组容量翻倍,并将旧数组元素迁移到新数组中。

一、扩容核心参数:

3个关键参数:

  • 容量(capacity):哈希表底层数组的长度,默认初始容量为16(必须是2的幂次)。
  • 负载因子(loadFactor):衡量数组填充程度的阈值比例,默认为0.75
  • 阈值(threshold):出发扩容的临界值,计算公式为:threshold=capacity*loadFactor(16*0.75=12)。

二、扩容触发条件:

当HashMap的元素数量size超过阈值时,触发扩容。
即:if(size>threshold) ->执行扩容

三、扩容完整流程(以JDK1.8为例)

JDK1.8中HashMap底层为 数组+链表+红黑树,扩容流程优化后更高效,步骤如下:

1.计算新容量:

新容量=旧容量×2

2.计算新阈值:

新阈值=新容量×负载因子

3.创建新数组:

根据新容量创建一个更大的数组。

4.迁移元素:

将旧元素中的所有元素(链表/红黑树节点)重新计算索引,迁移到新数组中。

四、关键:元素迁移的索引计算:

由于容量一直为2的幂次,JDK1.8中元素迁移时的新索引可以通过高位判断快速计算,无需重新计算哈希值。

  • 旧容量为oldCap(如 16),新容量为newCap = oldCap × 2(如 32)。
  • 元素在旧数组中的索引为oldIndex(通过 hash & (oldCap - 1) 计算)。
  • 新索引只有两种可能:
    若元素哈希值的第n位(n为oldCap的幂次,如 16 是 2⁴,n=4)为0 → 新索引 = oldIndex
    若第n位为1 → 新索引 = oldIndex + oldCap

五、举例:

假设我们有一个初始状态的HashMap:

  • 容量oldCap = 16(数组索引 0~15),阈值threshold = 12,负载因子0.75

步骤 1:触发扩容

当插入第 13 个元素时,size = 13 > threshold = 12,触发扩容:

  • 新容量newCap = 16 × 2 = 32(数组索引 0~31)。
  • 新阈值newThreshold = 32 × 0.75 = 24。

步骤 2:迁移元素(以两个元素为例)

假设旧数组中有两个元素,哈希值(简化后)如下:

  • 元素 A:hash = 0001 0101(二进制,共 8 位示意)
  • 元素 B:hash = 0011 0101

计算旧索引:

旧容量16的二进制是10000oldCap - 1 = 15(二进制01111)。

  • 元素 A 旧索引:hash & 15 = 0001 0101 & 0000 1111 = 0101 → 5。
  • 元素 B 旧索引:hash & 15 = 0011 0101 & 0000 1111 = 0101 → 5(与 A 哈希冲突,在旧数组索引 5 处形成链表)。

计算新索引:

新容量32是100000oldCap = 16的二进制是10000,关键看哈希值的第 4 位(从 0 开始数,对应 16 的幂次位):

  • 元素 A 的 hash 第 4 位:0001 0101 → 第 4 位是0(从右数第 5 位,因 0~3 位是低 4 位) → 新索引 = 旧索引5。
  • 元素 B 的 hash 第 4 位:0011 0101 → 第 4 位是1 → 新索引 = 旧索引5 + 16 = 21。

迁移结果:

  • 元素 A 从旧数组索引 5 迁移到新数组索引 5。
  • 元素 B 从旧数组索引 5 迁移到新数组索引 21。
    两者在新数组中不再冲突链表被 “打散”,查询效率提高。

六、JDK1.7与1.8扩容的核心差异:

请添加图片描述

七、总结:

  • HashMap通过"容量翻倍+元素迁移"实现扩容,核心目的是减少哈希冲突
  • JDK1.8的优化(如高效索引计算、尾插法)让扩容更高效且安全。
  • 实际开发中,若能预估元素数量,建议初始化时指定容量,如:(new HashMap<>(1000)),减少扩容次数以提升性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值