jdk 8 中 hashmap 采用“数组+链表+红黑树”三级结构,当单桶链表≥8且数组长度≥64时树化,退化阈值为6,结合哈希扰动与位运算索引提升均匀性,并优化扩容机制实现高效迁移。

HashMap 在 JDK 8 中的结构升级不是小修小补,而是针对高冲突场景下性能失控问题的一次系统性重构:用“数组 + 链表 + 红黑树”三级结构替代了 JDK 7 的纯链表设计,核心目标是把最坏情况下的操作时间从 O(n) 控制在 O(log n)。
链表退化成性能瓶颈,红黑树成为必要解法
当多个 key 哈希后落在同一个桶(数组索引)时,JDK 7 只能靠链表串起来。一旦攻击者或数据分布不均导致某条链表很长,get、put、remove 全部变成遍历操作——查一个元素可能要走几十甚至上百步。JDK 8 引入红黑树,就是为堵住这个漏洞。
- 链表查找是线性扫描,复杂度随长度线性增长
- 红黑树是自平衡二叉搜索树,高度始终维持在 log₂N 量级
- 同一桶内节点数 ≥ 8 且整个 table 长度 ≥ 64 时,才触发树化——避免小表过早引入树开销
树化与退化的双向阈值设计很务实
树不是越早建越好,也不是建了就永远不变。JDK 8 设置了三组联动阈值,兼顾效率与内存成本:
- TREEIFY_THRESHOLD = 8:单桶链表长度达到 8,启动树化评估
- MIN_TREEIFY_CAPACITY = 64:总数组长度不够 64,优先扩容而不是树化——先给空间再优化结构
- UNTREEIFY_THRESHOLD = 6:红黑树节点数 ≤ 6 时,自动还原为链表——去掉多余指针和颜色标记,轻装上阵
哈希计算和索引定位更抗碰撞
光有结构升级还不够,JDK 8 还优化了哈希值的生成方式,让 key 的 hashCode 分布更均匀:
- 原始 hash = key.hashCode()
- 扰动处理:hash = h ^ (h >>> 16),把高 16 位混入低 16 位
- 下标计算:(n - 1) & hash,其中 n 是 2 的幂,用位运算代替取模,又快又稳
这一步大幅降低了不同 key 落到同一桶的概率,从源头缓解冲突压力。
扩容机制同步进化,减少迁移成本
JDK 8 的 resize() 不再像 JDK 7 那样完全重哈希所有元素。它利用 2 的幂特性,让每个原桶里的元素只可能去两个新位置(原索引 or 原索引 + oldCap),通过高低位分离快速完成迁移,整体扩容效率更高、更可预测。
- 扩容后容量翻倍(如 16 → 32 → 64)
- 每个 Node 的新位置由 hash 的高位决定,无需重复调用 hashCode()
- 链表迁移保持插入顺序,红黑树迁移也保留树结构完整性











