hashmap扩容触发条件有三:一是put后size>threshold(如默认16容量、0.75负载因子,阈值为12,第13个元素触发);二是首次put初始化数组;三是链表长度达8且容量<64时优先扩容而非树化。

HashMap 的扩容触发不是靠“满了才动”,而是由三个核心参数协同判断:容量(capacity)、负载因子(loadFactor)和阈值(threshold)。默认情况下,只要元素个数 size > threshold,就会在 put() 操作后立即触发扩容。
扩容的三个明确触发时机
以下任一条件满足,resize() 就会被调用:
-
新增元素后 size 超过阈值:比如默认容量 16、负载因子 0.75,阈值 = 12;插入第 13 个新 key 时,
++size后变为 13,大于 12,立刻扩容。 - 首次 put 触发初始化:new HashMap() 不分配数组;第一次调用 put 时,table 为 null,强制执行 resize() 初始化数组(容量设为 16,阈值设为 12)。
- 链表准备树化但容量太小:当某个桶的链表长度达到 8,且当前数组容量 小于 64,不会直接转红黑树,而是先扩容(因为扩容后哈希更分散,可能避免树化)。
阈值是怎么算出来的?
阈值不是固定值,它随容量动态更新:
- 初始化时:threshold = 初始容量 × 负载因子(如 new HashMap() → 首次 put → capacity=16 → threshold=12)
- 扩容后:新 threshold = 新容量 × 负载因子(如从 16 扩到 32 → 新 threshold = 32 × 0.75 = 24)
- 注意:如果构造时传了初始容量(如
new HashMap(10)),HashMap 会自动向上取最近的 2 的幂(即 16),再算阈值。
为什么扩容必须是 2 的幂?
这是位运算定位下标的基础:
- 元素位置计算用的是
hash & (capacity - 1),不是hash % capacity。 - 只有当 capacity 是 2 的幂(如 16=2⁴,32=2⁵),capacity−1 的二进制才全为 1(如 15=0b1111),才能保证与运算结果均匀落在 [0, capacity−1] 区间。
- 这个设计不仅提速,还支撑了扩容时的“高位判断”优化:旧下标为 i 的元素,新位置要么是 i,要么是 i + 旧容量,无需全部重哈希。
不扩容的情况也要注意
有些操作看似“加了东西”,但不会导致 size 增加,因此不触发扩容:
- put 相同 key:只覆盖 value,size 不变
- putNullKey 或重复插入 null:null 的 hash 固定为 0,仍走覆盖逻辑
- 调用 clear() 后再 put:size 从 0 开始重新计数,阈值不变,但需重新填满才会再扩











