HashMap 1.7和1.8的区别

HashMap在1.7和1.8版本间有显著变化。1.7版本使用数组+链表,1.8版本引入了红黑树,当链表长度超过8且数组长度大于等于64时转为红黑树。1.7在put时采用头插法,可能导致环形链表,而1.8使用尾插法解决此问题。扩容时,1.7通过改变hashSeed,1.8则保持键的hash值不变,依赖rehash策略。对于键为null的情况,两版本都将它们存储在table[0]。
摘要由CSDN通过智能技术生成

HashMap 1.7和1.8的区别

底层结构

1.7: 底层结构为 数组 + 链表

底层数组为 entry 数组 加载方式类似于单例模式的饿汉式 当new HashMap() 的时候就将数组初始化完成。

1.8: 底层结构为 数组 + 链表 + 红黑树

底层数组为 Node 数组 加载方式类似于单例模式的懒汉式 当首次执行put操作时会判断数组是否存在,如果不存在将执行resize()方法进行初始化

//将链表转化为红黑树的阀值
static final int TREEIFY_THRESHOLD = 8;
 
//将红黑树转回为链表的阀值
static final int UNTREEIFY_THRESHOLD = 6;
 
//将链表转为红黑树的最小entry数组的长度为 64
static final int MIN_TREEIFY_CAPACITY = 64;

当链表的长度 > 8,且entry数组的长度>= 64时,才会将链表转为红黑树。
bitCount初始值为0 所以 >= TREEIFY_THRESHOLD - 1 即为 >= 8
在判断前会执行 p.next = newNode(hash, key, value, null); 增加一个新节点
所以最后的判断条件为 链表长度 > 8

//此处遍历链表
for (int binCount = 0; ; ++binCount) {
    //遍历到链表最后一个节点
    if ((e = p.next) == null) {
        p.next = newNode(hash, key, value, null);
        //如果链表元素个数大于等于TREEIFY_THRESHOLD - 1
        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
            //红黑树转换逻辑
            treeifyBin(tab, hash);
        break;
     }
    if (e.hash == hash &&
        ((k = e.key) == key || (key != null && key.equals(k))))
        break;
     p = e;
}

执行put操作

1.7: 头插法 后来的值被查找的可能性更大一点,提升查找的效率。但是当数组扩容时会存在 环形链表 问题。

1.8: 尾插法 解决环形链表问题

环形链表

A->B->C 当扩容后 A、B还是在同一个位置,A先添加后,B再添加,头插法。所以会出现B->A->B的环形链表
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

扩容时

1.7:是通过更改hashSeed值修改节点的hash值从而达到rehash时的链表分散。 插入数据之前扩容

1.8:键的hash值不会改变,rehash时根据(hash&oldCap)==0将链表分散。 插入数据成功之后扩容

在这里插入图片描述

Key 为 NULL

1.8中没有区分键为null的情况,而1.7版本中对于键为null的情况调用putForNullKey()方法。但是两个版本中如果键为null,那么调用hash()方法得到的都将是0,所以键为null的元素都始终位于哈希表table【0】中。

个版本中如果键为null,那么调用hash()方法得到的都将是0,所以键为null的元素都始终位于哈希表table【0】中。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值