HashMap扩容在size > capacity × loadFactor(如默认13>12)或链表≥8且数组长度<64时触发,由putVal自动完成,保障高性能。

Java 中 HashMap 的容量自动扩容是其保障高性能的核心机制之一,整个过程由内部逻辑自动完成,无需手动干预。关键在于理解“什么时候扩”和“怎么扩”两个层面。
触发扩容的两个明确条件
扩容不是每次 put 都发生,而是在特定条件下由 putVal() 方法末尾检查并触发:
-
主条件:元素总数超过阈值 —— 即
size > capacity × loadFactor。默认初始容量为 16、负载因子为 0.75,所以第 13 个元素插入时(13 > 12)就会触发扩容。 -
辅助条件:链表转树前的兜底扩容 —— 当某个桶中链表长度 ≥ 8,但当前数组长度 treeifyBin() 不会直接转红黑树,而是优先调用
resize()。这是为了通过扩容自然分散元素,比树化更轻量、更有效。
扩容时如何计算新容量与新阈值
扩容不是简单翻倍,而是有边界控制和初始化兼容逻辑:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 若旧容量大于 0(即已初始化),新容量 =
oldCap << 1(左移一位,等价于 ×2),上限为1 << 30(即 2³⁰ = 1,073,741,824)。 - 若旧容量为 0(首次 put),则按构造逻辑确定:若构造时指定了初始容量,会通过
tableSizeFor()调整为不小于该值的最小 2 的幂;否则使用默认值 16。 - 新阈值 =
newCapacity × loadFactor;若原阈值已设(如通过带参构造传入),也可能直接继承或按比例翻倍。
元素迁移采用高低位拆分优化(JDK 8+ 核心改进)
旧数组中每个桶的元素迁移到新数组时,并非全部重新哈希(hash & (newCap - 1)),而是利用容量为 2 的幂的特性做位运算加速:
立即学习“Java免费学习笔记(深入)”;
- 对每个节点,只看其 hash 值在「旧容量对应二进制最高位」上的值(即
e.hash & oldCap)。 - 结果为 0 → 放入新数组的原下标位置(
loHead链)。 - 结果非 0 → 放入新数组的
原下标 + oldCap位置(hiHead链)。 - 单节点直接定位;链表被拆成两个子链,顺序保持不变;红黑树则调用
split()拆分为两棵子树,节点数 ≤6 时退化为链表。
扩容后的状态更新
迁移完成后,HashMap 会立即切换引用:
- 将
table指针指向新创建的newTab数组。 - 更新
threshold为新阈值,下次扩容临界点随之上移(例如从 12 → 24 → 48…)。 - 旧数组对象失去引用,等待 GC 回收。

















