HashMap 采用懒加载,首次 put() 时由 resize() 初始化底层数组;若构造时指定容量则直接使用(对齐至2的幂),否则默认16,并同步计算阈值(如16×0.75=12)。

Java HashMap 的 resize() 方法不仅负责常规扩容,也承担**首次初始化数组**的任务——也就是说,HashMap 是懒加载的,真正创建底层数组(table)发生在第一次调用 put() 时,由 resize() 完成。
首次调用 resize() 就是初始化
当你执行 new HashMap(),内部的 table 字段为 null,此时并未分配任何数组。只有当第一次 put() 被调用时,putVal() 检测到 table == null,就会立刻触发 resize() 来初始化。
- 源码中会判断:
if (oldTab == null)→ 进入初始化分支 - 若构造时指定了初始容量(如
new HashMap(32)),则oldThr(旧阈值)可能已设为该值,newCap直接取该值(向上对齐到 2 的幂) - 若使用无参构造,则默认走
DEFAULT_INITIAL_CAPACITY = 16
初始化时的关键参数设定
初始化不是简单地 new 一个长度为 16 的数组,它同步计算并设置后续扩容所需的阈值:
-
新容量(newCap):取
oldThr(若有)或默认 16;确保是 2 的幂(如传入 10 → 自动提升为 16) -
新阈值(newThr):若
oldThr > 0(即构造时指定了容量),则newThr = oldThr;否则按newCap × loadFactor计算 → 默认为16 × 0.75 = 12 - 最终赋值:
table = newTab(完成数组创建),threshold = newThr
扩容与初始化共用同一套逻辑
resize() 是统一入口,通过判断 oldCap 值区分场景:
-
oldCap == 0→ 初始化:分配数组、设阈值、不迁移元素(因无旧数据) -
oldCap > 0→ 真正扩容:容量翻倍(oldCap )、阈值翻倍、遍历旧数组迁移所有节点 - 无论哪种情况,新数组长度始终是 2 的幂,以保证
(n - 1) & hash位运算寻址正确高效
为什么设计成懒初始化?
这是典型的性能优化策略:
- 避免无意义内存分配:如果 Map 创建后一直没存数据,就不需要数组空间
- 延迟计算开销:哈希扰动、索引定位等逻辑推迟到真正写入时才发生
- 与 JDK 多版本保持一致:从 JDK 7 到 JDK 22,这一行为未改变
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











