hashmap扩容在size超过threshold(容量×负载因子)时触发,目的是控制哈希冲突、维持o(1)查询效率;扩容时容量翻倍并保持2的幂,通过高位判断实现元素高效迁移,避免重哈希。

Java HashMap 扩容不是等数组“满了”才发生,而是在元素数量逼近设计容量时就主动触发,核心目标是控制哈希冲突、维持平均 O(1) 查询效率。
扩容的触发条件
扩容由 size > threshold 这一判断决定,其中:
- size 是当前已存储的键值对数量(不是数组长度)
- threshold = 当前容量 × 负载因子(默认 0.75)
- 初始容量为 16 → 阈值 = 12 → 插入第 13 个元素时触发第一次扩容
- 注意:仅当待插入位置(桶)非空时才真正执行 resize;若桶为空,即使 size 刚超阈值,也可能延迟到下一次 put
扩容时发生了什么
调用 resize() 方法后,HashMap 会完成两个关键动作:
-
创建新数组:容量翻倍(如 16 → 32),且严格保持为 2 的幂次方,确保后续
hash & (capacity - 1)运算能均匀散列 -
迁移旧元素:不重新计算全部哈希值,而是利用高位比特快速判断新下标:
- 若原哈希值的“扩容位”为 0 → 元素留在原下标
- 若为 1 → 新下标 = 原下标 + 旧容量(例如从下标 5 移至 5 + 16 = 21)
链表与红黑树在扩容中的处理
JDK 1.8 中,扩容过程会保留原有结构形态:
- 普通链表节点逐个迁移,顺序可能反转(头插法变尾插法优化后已改善)
- 红黑树节点同样迁移,若迁移后某桶中节点数 ≤ 6,则退化回链表
- 迁移过程中仍遵守树化阈值(默认 8)和退化阈值(默认 6),保证结构合理性
为什么容量必须是 2 的幂
这是底层定位逻辑决定的:
- 下标计算用的是
hash & (capacity - 1),不是取模% - 只有 capacity 是 2 的幂,
capacity - 1的二进制才全为 1(如 16→15 即 1111),才能让 & 运算等价于取模且高效 - 若用奇数或非 2 幂数,会导致大量下标永远无法命中,空间浪费 + 冲突激增
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











