深挖 HashMap:JDK 1.7 与 1.8 的区别详解

23年硕士毕业半年被裁后,一个月斩获大厂offer,“跟着周哥走,offer手里有”。文末有周哥50+场面试总结出的必会面试题。

HashMap在jdk1.7和jdk1.8中的区别?

答:

通存储结构

  • JDK 1.7 中的 HashMap 使用数组 + 链表的方式来存储元素。数组的每个元素即为一个桶,每个桶可能包含一个链表,多个元素通过链表连接在同一个桶中

  • JDK 1.8 对 HashMap 进行了优化,引入了红黑树。当链表长度达到一定阈值(默认是8)时,链表会转换为红黑树。这是为了提高在哈希冲突较严重时的查询效率,将链表的线性查找优化为红黑树的对数查找。

哈希冲突解决方式

  • jdk1.7中,当多个不同的键映射到相同的桶时,它们会形成一个链表。在查找键时,HashMap 遍历该链表,先hashcode后equals 方法判断是否为目标键。采用头插法插入数据。

  • JDK 1.8 对 HashMap 进行了优化,引入了红黑树。当链表长度达到一定阈值(默认是8)时,链表会转换为红黑树。这是为了提高在哈希冲突较严重时的查询效率,将链表的线性查找优化为红黑树的对数查找,O(logn)<O(n)。采用尾插法插入数据。

    • jdk1.8采用尾插法插入链表节点,原因在于

      • 尾插法相比头插法在处理并发场景时,特别是多线程并发写入时,减少了对链表头部的竞争,提升了并发性能。这是为了更好地适应多核处理器的并发特性,减小了线程之间的竞争,提高了整体的性能表现。
      • CPU缓存对程序的性能至关重要。如果数据结构中的元素顺序与CPU缓存行对齐,可以大大提高缓存命中率,从而提高程序的执行效率。

扩容

  • jdk1.7中当 HashMap 中的元素数量达到容量 * 负载因子(默认是0.75)时,会触发扩容操作。扩容操作会将桶的数量翻倍,并重新计算每个元素的桶位置。

  • 扩容的方式相对于 JDK 1.7 有所改进。在 JDK 1.8 中,扩容不再采用逐个移动元素的方式,而是使用更高效的数组复制方法。

    • 扩容时机

        1. putVal中判断数组的容量为空时,初始化数组table,初始化桶数组长度为16,阈值为16* 0.75 = 12。
        1. 当元素数量size达到阙值时即size > loadfactor * capacity 时,也是在putVal函数中,调用resize(),扩容后的数组大小是原数组的2倍,将原来的元素重新hash放入到新的散列表中去。
    • 扩容过程

      • 创建一个新的数组,其容量为旧数组的两倍,并重新计算旧数组中结点的存储位置。元素在新数组中的位置只有两种,原下标位置或原下标+旧数组的大小。

对key = null的处理

  • jdk1.7中,hashmap会直接将null key放到index = 0的位置,遍历table[0]的Entry链表,寻找key的null的节点,找到后覆盖,未找到就添加一个null

  • jdk1.8中,是先计算null的hash值的到0,然后和其他key一样用(n-1)& hash值计算得到index=0,然后,后续操作和他其他键一样。

  • 注:hashtable中不支持key为null

以上内容出自本人整理的面试秘籍。 链接: https://pan.baidu.com/s/1o014Ems8diV0D3h8K15olA?pwd=fi3x 提取码: fi3x 复制这段内容后打开百度网盘手机App,操作更方便哦

本文由 mdnice 多平台发布

  • 17
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值