HashMap底层数组容量≥64才允许链表树化,旨在区分临时性哈希冲突与结构性异常,避免小容量时因空间拥挤导致的假性堆积而误树化;64是兼顾扩容成本与查找稳定性的工程经验阈值。

Java HashMap 要求底层数组容量 ≥ 64 才允许链表树化,核心是为了区分“临时性哈希冲突”和“结构性哈希异常”,避免在小容量场景下过早引入红黑树带来的额外开销。
防止小表频繁树化与退化
小容量数组(如 16、32)时,哈希冲突往往不是 key 的 hash 分布问题,而是桶太少、“空间太挤”导致的假性堆积。此时扩容(翻倍)就能快速分散元素,成本远低于树化——红黑树涉及节点着色、旋转、比较器校验等操作,内存占用也更高。若在容量 16 时就允许树化,后续 resize 还得把红黑树拆解、再平衡、甚至退化,徒增负担。
- 容量 16 → 冲突链表达 8:触发 resize,变成容量 32
- 容量 32 → 同一桶仍达 8:再次 resize,变成容量 64
- 容量 64 → 同一桶仍 ≥ 8:才判定为大概率非随机冲突,值得树化
匹配泊松分布的统计合理性
阈值 8 来源于哈希均匀分布下的泊松建模(λ = 0.5),P(X ≥ 8) ≈ 10⁻⁶,即百万次插入中仅一次可能自然出现长度 ≥ 8 的链表。当数组经过两次扩容(16→32→64)后仍存在这种极低概率事件,说明 hash 函数或 key 分布存在系统性偏差——这时树化不是为了“提速”,而是为了保障最坏情况下的查找稳定性(从 O(n) 降到 O(log n))。
工程权衡:64 是平衡点
64 不是理论推导值,而是实测经验阈值:
立即学习“Java免费学习笔记(深入)”;
- 若设为 16:小表树化泛滥,旋转开销压倒收益
- 若设为 512:长链表长期存在,O(n) 查找拖慢高频读场景
- 64 刚好覆盖常见业务规模(如万级数据),兼顾扩容次数可控与结构升级必要性
源码逻辑强制兜底
treeifyBin() 方法里明确检查:if (tab == null || tab.length → 直接 resize(),跳过所有树化逻辑。这意味着即使你手动构造一个长度 15 的链表,只要 table.length 是 32,它就永远保持链表形态,不会转树。


















