HashMap在链表长度≥8且数组长度≥64时将链表转为红黑树;若数组长度不足64,则优先扩容而非树化,以改善哈希分布、减少碰撞。

HashMap 在链表长度达到 8 且数组长度不小于 64 时,会将该桶(bin)的链表转为红黑树。这不是简单“替换结构”,而是一套有约束、有重建逻辑的转换过程。
触发条件必须同时满足
链表转红黑树不是只看长度。JDK 1.8 中需同时满足两个硬性条件:
- 当前桶中链表节点数 ≥ 8(即 TREEIFY_THRESHOLD = 8)
- 整个 HashMap 的底层数组(table)长度 ≥ 64(即 MIN_TREEIFY_CAPACITY = 64)
若数组太小(如刚初始化或扩容前),即使某链表很长,也优先选择扩容(resize)而非树化——因为扩容后哈希分布更均匀,能自然缓解碰撞。
树化前先检查是否该扩容
当 put 操作发现某桶链表长度达到 8,HashMap 不会立刻建树。它会先调用 treeifyBin() 方法:
- 先判断 table.length
- 否则才真正进入树化流程:遍历链表,构造 TreeNode 节点,并构建左倾红黑树结构
这个设计避免了小容量下过早树化带来的额外开销(TreeNode 比 Node 更占内存,且小数组下树形优势不明显)。
树化是重新构造,不是就地升级
链表节点是 Node
- 遍历原链表,为每个元素 new 一个 TreeNode 实例
- 根据 key 的 hash 值和 Comparable 接口(或 tieBreakOrder)确定大小关系
- 按红黑树插入规则逐个插入,同时维护 red/black 属性与树平衡(通过 rotate 和着色)
- 完成后,桶的首节点指向新树的 root,原链表对象被 GC 回收
注意:TreeNode 保留了 next 引用,形成“双向链表 + 树”混合结构,既支持树操作,也兼容迭代器的链表遍历逻辑。
退化回链表也有明确时机
红黑树不是一劳永逸。当执行 remove 或 resize 导致某树中节点数 ≤ 6 时,会触发 untreeify(),把 TreeNode 链表还原为普通 Node 链表:
- 遍历 TreeNode 链表,为每个节点 new 一个普通 Node
- 重建单向链表结构,丢弃 tree 相关字段(parent/prev/red 等)
- 桶头指针指向新链表首节点
阈值设为 6(而非 8 的对称值)是为了避免在 7 附近频繁树化/反树化,提供缓冲区间。


















