在代码的海洋里,女码农们总是被贴上“硬核”、“理性”的标签,但你知道吗?

在深夜的键盘敲击声中,藏着多少不为人知的emo时刻?

接下来的这篇帖子,简直就是咱们程序员圈里的“emo大赏”,看得人心都揪成了一团乱麻。

想象一下,你正埋头苦干,代码改了一版又一版,领导却说:“感觉差点意思,再改改吧。”

这还不是最绝的,最绝的是他自己也说不清到底差哪儿!外包妹子直接泪崩,这哪是改代码啊,简直是改命啊!

甲方妹子那边也是,大领导一顿“爱的教育”,项目经理接着补刀,排期排得比高考还紧张,不哭都难!

一个需求扔过来,表在哪?字段啥意思?业务逻辑怎么绕?全靠自己摸索,领导还指望你秒懂。

这哪是工作啊,简直是玩“大家来找茬”的高级版,还TM是地狱难度!

但生活嘛,总得继续不是?

女码农们只能收起泪水,继续埋头苦干。

心里头那个“丧”啊,就像是一场永远不会停的“雨季”。

但咱们还是得笑中带泪地坚持,毕竟,“打工人,打工魂,打工都是人上人”(虽然这话听起来有点自我安慰的味道)。

说真的,技术圈这个地儿,有时候真的挺“丧”的。

大家都在焦虑中挣扎,却又找不到出口。

就像是一群“孤独患者”,在“代码雨林”里迷失了方向。

每次看到这样的帖子,都忍不住想抱抱自己,然后说一句:“原来你也在这里”。

。。。


言归正传。今天要分享的面试题是:

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 中,扩容不再采用逐个移动元素的方式,而是使用更高效的数组复制方法。

    • 扩容时机

      • putVal中判断数组的容量为空时,初始化数组table,初始化桶数组长度为16,阈值为16* 0.75 = 12。
      • 当元素数量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

本文由mdnice多平台发布


周哥的offer秘籍
1 声望0 粉丝

23年硕士毕业半年被裁,一个月斩获大厂offer。面试经历50+,擅长校招社招求职笔试和面试全流程,擅长简历撰写。跟着周哥走,offer手里有!关注周哥不迷路!