在JDK 1.8中,除了引入红黑树外,HashMap还进行了哪些其他改动?请从数据结构、存储方式、哈希算法、扩容机制、链表插入方式、get过程、遍历顺序等方面说明。
考察说明
考查对JDK 1.8 HashMap底层实现细节的全面掌握,是否了解除红黑树外的其他优化与调整。
回答思路
- 【回答框架 1】JDK 1.8 HashMap将底层数组+链表改为数组+链表+红黑树,当链表长度超过8且数组长度大于64时转为红黑树,以减少哈希冲突严重时的查找时间。
- 【回答框架 2】存储方式上,1.8将原先的Entry改造为Node,引入TreeNode结构;1.7的哈希算法扰动四次,1.8简化为一次异或,提高了计算效率。
- 【回答框架 3】扩容机制上,1.7扩容时重新计算每个元素的hash并插入,可能形成环形链表;1.8扩容时,通过判断hash的新增位是否为0,将元素分为低位和高位两组,原位置不变或移动旧容量大小,保持顺序。
- 【回答框架 4】链表插入方式从1.7的头插法改为1.8的尾插法,避免在多线程扩容时因头插导致链表循环。
- 【回答框架 5】get过程在1.8中也会根据节点类型判断:如果是红黑树节点则走树查找,否则遍历链表。整体上,1.8的HashMap在并发环境下虽不保证线程安全,但避免了部分死循环问题。
- 【关键点 1】引入红黑树,链表长度超过8且数组长度大于64时转为红黑树。
- 【关键点 2】哈希扰动从4次减为1次,提升效率。
- 【关键点 3】扩容时按高低位拆分,避免重哈希,且扩容后元素位置要么不变要么加旧容量。
- 【关键点 4】链表插入从头插改为尾插,避免并发扩容时出现环形链表。
- 【关键点 5】存储节点由Entry改为Node,更有扩展性。
- 【易错点 1】误以为红黑树是主要改动,忽略其他细节。
- 【易错点 2】将头插法误认为尾插法,或反之。
- 【易错点 3】错误认为1.8 HashMap完全线程安全,实际上仅避免死循环,仍可能丢失数据。