jdk1.7 vs jdk 1.8 之HashMap

本文探讨了JDK1.7和1.8中HashMap的区别,包括为什么使用指数次幂设置数组长度、加载因子选择0.75的原因、链表长度设为8的考量,以及不同版本的扩容策略。JDK1.8引入红黑树以优化长链表查询性能,并通过高低位拆分避免了扩容时的死锁问题,提高了并发性能。
摘要由CSDN通过智能技术生成

HashMap

JDK1.7 数组+链表

JDK1.8 数组+链表,链表长度>8&&数组长度>64 --> 红黑树

1.7

根据hash计算index,一般index= hash % length, 让键值对均匀分配在数组中

插入元素时可能产生 哈希冲突,所以产生了链表

链表的缺陷: 查询O(N)

为什么需要指数次幂?

负载因子:0.75

initialCapacity数组的初始长度:2的指数次幂

如果自己定义的不是,在put时在inflateTable里改成大于这个数的第一个2的指数次幂

在这里插入图片描述

提高效率:取模运算在底层需要换算成2进制,计算效率:加>×>除>mod,所以用h&(length-1)代替

当length是2的指数次幂,才会相等。

在这里插入图片描述

这样保证求出的index在length范围之内,不会越界

加载因子为什么是0.75

loadfactor=1,可以最大化利用空间

loadfactor=0.5,可以尽量避免哈希冲突,查询效率高,节省时间,当用到一半就扩容

为什么链表长度是8

产生hash碰撞的时候,放在一个桶里面,放在链表后面的概率符合泊松分布

泊松分布:负载因子0.75时,随着链表里节点的增加,定位到同一个桶的概率越来越小,产生红黑树的概率所以也不大,所以jdk8比7提高了8-10%的性能

扩容

jdk7

put时,addEntry,如果size大于阈值且当前桶不为空,就会扩容resize

resize: 扩容需要转移数组transfer

多线程时会出现环

transfer的作用

在这里插入图片描述

问题:会产生死锁,因为会颠倒链表中的位置

jdk8

如果链表长度达到8

  • 如果数组长度大于64,则转化为红黑树
  • 如果数组长度小于64,则进行resize扩展

首先,定义了4个新的变量:

  • loHead, loTail

  • hiHead, hiTail

当前hashcode & oldCap(eg.16)

  • 结果要么0000全是0,要么是16

(如果本身的hashcode<16,则&的结果为0,如果hashcode>=16,则&的结果为16

在这里插入图片描述

如果&的结果是0,则是低位,否则是高位

在这里插入图片描述

迁移过程

在这里插入图片描述

loTail断掉,loHead在新数组下标相同的位置

hiTail断掉,hiHead在新数组下标原下标+原数组长度

好处:

用高低位避免了死锁,

没有重新进行hash计算,

几乎算是均匀的拆分,

避免了链表环的产生,

这也是为什么要2的指数次幂的原因

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值