HashMap 底层数据结构
面试官问:"HashMap 底层是什么数据结构?"
候选人小梁答:"JDK 8 是数组加链表,数组里存链表节点。"
面试官追问:"JDK 8 之后加了什么?"
小梁说:"红黑树。"
面试官追问:"为什么加红黑树?什么情况下会树化?"
小梁说:"链表太长的时候...大概是8?"
面试官:"那为什么要用红黑树而不是其他树?"
小梁答不上来。
【面试官心理】 这道题考查的是候选人对 HashMap 演进历史的理解。能说出"JDK 7 的扩容死循环"和"JDK 8 的改进"的候选人,说明真正研究过 HashMap 的历史和设计意图。
一、数据结构演变 🔴
二、JDK 7:数组 + 链表 🔴
2.1 Entry 节点
2.2 JDK 7 HashMap 结构
所有节点组成一个 Entry 数组,每个桶(bucket)中是一个链表(通过 next 指针链接)。
2.3 JDK 7 的致命问题:扩容死循环
死循环的原因:
⚠️
JDK 7 的 HashMap 在高并发下扩容可能导致死循环和 CPU 100%。这是 Java 历史上最著名的并发 bug 之一。JDK 8 通过改变 transfer 的顺序(非递归、头插改尾插)解决了这个问题。
三、JDK 8:数组 + 链表 + 红黑树 🔴
3.1 Node 节点(JDK 8+)
3.2 JDK 8 HashMap 结构
3.3 为什么用红黑树而不是其他树
为什么不用 AVL?
- AVL 树比红黑树更严格平衡
- 查找性能更好(因为更平衡)
- 但插入和删除的代价更高(更多旋转操作)
- HashMap 的场景:插入和删除远多于查找,且不需要严格平衡
- 红黑树的插入/删除代价更小,更适合 HashMap
为什么不用 B+ 树?
- B+ 树是多叉树,适合磁盘存储(数据库索引)
- HashMap 在内存中,不需要多叉优化
四、红黑树化阈值 🔴
为什么是 8 和 6(不是对称的)?
【面试官心理】 能说出泊松分布和阈值设计原因的候选人,说明看过 HashMap 的源码注释,这是 P6+ 的标准要求。