hashmap用链地址法处理哈希冲突,满足链表≥8且数组长度≥64时树化为红黑树,节点≤6时退化回链表,兼顾轻量与效率。

Java HashMap 用“链地址法”处理哈希冲突,再通过动态结构升级(链表 ↔ 红黑树)来兼顾小数据的轻量与大数据的效率。
哈希冲突是怎么产生的
不同 key 调用 hashCode() 可能算出相同哈希值;再经扰动函数和 (n - 1) & hash 运算后,又映射到同一个数组下标(桶),这就发生了哈希冲突。
比如 "A" 和 "Q" 的 hashCode 分别是 65、81,对长度 16 的数组做位运算后都落在索引 1 上——这是典型的小范围碰撞。
- 冲突无法避免,只能合理应对
- HashMap 不拒绝冲突,而是为每个桶预留容纳多个元素的能力
- null key 是特例:固定放在索引 0,且只允许一个
链表是默认的冲突解决方案
当桶中已有元素,新元素 key 不等于已有 key(通过 equals() 判断),就以链表形式挂在后面。
- 插入在链表尾部(JDK 1.8 起),避免头插导致的扩容死循环问题
- 查找时需遍历链表,最坏时间复杂度 O(n)
- 只要 key 正确重写 hashCode() 和 equals(),链表就能准确定位
什么时候转成红黑树
不是链表一长就转。必须同时满足两个硬性条件:
- 当前桶内链表节点数 ≥ 8(TREEIFY_THRESHOLD = 8)
- 整个 HashMap 的桶数组长度 ≥ 64(MIN_TREEIFY_CAPACITY = 64)
缺一不可。比如数组才 16,即使某个桶链表长达 12,也不会树化——因为大概率是容量太小、没及时扩容,而不是 key 设计有问题。
转树后,查找/插入/删除退化为 O(log n),显著优于长链表的线性扫描。
红黑树也会退化回链表
树不是一劳永逸的。当执行 remove() 或 resize() 后,某棵树的节点数 ≤ 6(UNTREEIFY_THRESHOLD = 6),就会自动拆解为链表。
- 节点少时,链表内存更省、操作更直接
- 避免为几个元素维护复杂的树结构和着色逻辑
- 这个过程是平滑的,用户无感知
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











