当前位置: 首页 > news >正文

深入理解 Java HashMap 扩容机制:从源码到原理全解析

一、为什么需要扩容?

HashMap 底层是一个数组 + 链表/红黑树的结构。数组长度是固定的,随着元素不断插入,哈希冲突概率增大,链表越来越长,查询效率从 O(1) 退化为 O(n)。

为了维持高效的查询性能,HashMap 在元素数量达到一定阈值后会自动进行扩容(resize)。

二、核心参数

参数默认值说明
DEFAULT_INITIAL_CAPACITY16初始容量,必须是 2 的幂
DEFAULT_LOAD_FACTOR0.75f负载因子
MAXIMUM_CAPACITY2^30最大容量
thresholdcapacity × loadFactor扩容阈值

扩容触发条件:

当前元素数量(size)> threshold(容量 × 负载因子)

默认情况下:16 × 0.75 = 12,即插入第 13 个元素时触发扩容。

三、扩容策略:容量翻倍

每次扩容,新数组容量 =旧容量 × 2

// JDK 8 源码(resize 方法节选) int newCap = oldCap << 1; // 左移1位 = ×2 int newThr = oldThr << 1; // 阈值也同步翻倍

容量始终保持 2 的幂次方,这是 HashMap 设计的核心约束,与后续的位运算寻址密切相关。

四、扩容全过程(JDK 8)

4.1 resize() 方法整体流程

final Node<K,V>[] resize() { Node<K,V>[] oldTab = table; int oldCap = (oldTab == null) ? 0 : oldTab.length; int oldThr = threshold; int newCap, newThr = 0; if (oldCap > 0) { // 已达最大容量,不再扩容 if (oldCap >= MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return oldTab; } // 正常扩容:容量和阈值均翻倍 else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && oldCap >= DEFAULT_INITIAL_CAPACITY) newThr = oldThr << 1; } else if (oldThr > 0) newCap = oldThr; // 使用指定初始容量 else { // 使用默认值初始化 newCap = DEFAULT_INITIAL_CAPACITY; newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY); } // 创建新数组 Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap]; table = newTab; // 将旧数组元素迁移到新数组 // ...(见下文) return newTab; }

4.2 数据迁移(rehash)

扩容后,所有元素需要重新计算在新数组中的位置。

JDK 8 的优化:利用容量是 2 的幂次这一特性,元素在新数组中的位置只有两种情况:

  • 原位置不变:新增高位 bit 为 0
  • 原位置 + 旧容量:新增高位 bit 为 1
// 判断高位 bit if ((e.hash & oldCap) == 0) { // 放到低位链表(原位置) } else { // 放到高位链表(原位置 + oldCap) }

这个设计避免了重新计算 hash,极大提升了扩容效率。

图示说明(以 oldCap=16 为例):

五、链表与红黑树的处理

JDK 8 中,链表长度 ≥ 8 时会转为红黑树。扩容时对两种结构分别处理:

5.1 链表拆分

// 将链表拆分为两条:lo(低位)和 hi(高位) Node<K,V> loHead = null, loTail = null; Node<K,V> hiHead = null, hiTail = null; Node<K,V> next; do { next = e.next; if ((e.hash & oldCap) == 0) { // 低位链表 if (loTail == null) loHead = e; else loTail.next = e; loTail = e; } else { // 高位链表 if (hiTail == null) hiHead = e; else hiTail.next = e; hiTail = e; } } while ((e = next) != null); if (loTail != null) { loTail.next = null; newTab[j] = loHead; } if (hiTail != null) { hiTail.next = null; newTab[j + oldCap] = hiHead; }

5.2 红黑树拆分

红黑树同样按高低位拆分。拆分后:

  • 若子树节点数 ≤ 6,退化回链表(untreeify
  • 若节点数 > 6,重新构建红黑树(treeify

六、疑问

JDK 7 与 JDK 8 扩容对比

对比项JDK 7JDK 8
数据结构数组 + 链表数组 + 链表 + 红黑树
插入方式头插法尾插法
rehash 方式重新计算 hash 位置位运算优化,无需重新 hash
并发问题头插法导致死循环尾插法规避了死循环问题

⚠️JDK 7 头插法的并发危险:多线程扩容时,头插法可能导致链表成环,引发get()死循环。JDK 8 改为尾插法解决了这一问题,但 HashMap 仍非线程安全,多线程场景请使用ConcurrentHashMap

负载因子为什么是 0.75?

这是空间与时间的权衡:

  • 过小(如 0.5):扩容频繁,空间浪费多,但冲突少
  • 过大(如 1.0):内存利用率高,但冲突多,链表变长,查询慢
  • 0.75:在泊松分布下,桶中元素碰撞概率较低,综合性能最优

官方注释中也提到,在理想随机 hash 下,0.75 的负载因子使得链表长度超过 8 的概率约为 0.00000006,极低。

初始容量的选择?

如果能预估元素数量,建议手动指定初始容量,避免多次扩容带来的性能损耗:

// 预计存放 1000 个元素 // 初始容量 = 预计数量 / 负载因子 + 1 int initialCapacity = (int)(1000 / 0.75) + 1; // ≈ 1334,HashMap 会向上取2的幂 = 2048 Map<String, Object> map = new HashMap<>(initialCapacity);

或者直接使用 Guava 的工具方法:

// Guava Map<String, Object> map = Maps.newHashMapWithExpectedSize(1000);

七、总结

要点说明
触发条件size > capacity × loadFactor
扩容倍数新容量 = 旧容量 × 2
迁移优化高位 bit 判断,避免重新 hash
链表/树处理拆分为高低位两组,按长度决定链表或树
线程安全HashMap 非线程安全,并发请用 ConcurrentHashMap
http://www.jsqmd.com/news/470613/

相关文章:

  • 4步实现高效直播内容保存:面向内容创作者的抖音直播下载与管理工具
  • 考试云全功能在线认证考试解决方案:解密传统认证四大核心痛点
  • 基于MPC算法的自动驾驶控制-速度控制的仿真研究
  • 基于MATLAB的决策树数据分类预测实战
  • 【Matlab】垂直起降无人机悬停精度优化
  • GaitPart步态识别算法研究与实现:基于部件关系图与可见性门控的深入分析
  • 苍穹外卖day3.02
  • 车辆三自由度动力学MPC跟踪双移线仿真研究:Matlab与Simulink联合应用
  • Ofd2Pdf:多模式转换引擎实现OFD到PDF的高效格式转换
  • 2026服装ERP系统选型以及实施成本评估,这几个关键维度千万别漏!
  • 别再徒手写前端了:Gradio让AI应用落地快10倍
  • ISO/GB高强度螺栓选型指南与性能对比_FES上海紧固件展
  • 2026全景技术横评:8款主流AI写作软件底层架构解析与实测选型指南
  • 家校沟通不用慌!高情商话术,轻松化解家长矛盾
  • 2026年SEVC SCI2区,基于特殊编码和新颖优化策略的离散进化算法求解旅行商问题,深度解析+性能实测
  • OpenClaw入门:从部署到QQ机器人实战
  • 一文读懂国商联集团等离子癌细胞清除舱的核心原理与优势
  • 微电网两阶段鲁棒优化容量配置:应对风光负荷不确定性
  • Power BI知识拓展:筛选器vs切片器
  • points包含内部点、边界点、初始点
  • 2026年靠谱的衣柜全屋定制厂家推荐:全屋定制生态板/儿童环保全屋定制优质供应商推荐 - 行业平台推荐
  • 沈阳美容美发短期速成学校
  • Python基于flask的医疗挂号就诊平台
  • DigVPS 测评 - 蔭雲(YINNET)上新法國ISP VPS 产品,新品七折出售中。
  • Python基于flask的在线广告推荐系统数据分析可视化大屏
  • 用OpenClaw AI构建自己的智能体
  • 2026年靠谱的铝镁锰金属屋面公司推荐:钛锌板金属屋面/立边咬合金属屋面优质供应商推荐 - 行业平台推荐
  • 职场人进阶指南:2026年这3张AI证书让你升职加薪快人一步
  • 计及电转气协同的含碳捕集与垃圾焚烧虚拟电厂优化调度 关键词:碳捕集 虚拟电厂 需求响应 优化调...
  • 思迈特软件入选广州市中小企业数字化转型牵引单位