HashMap在JDK1.7和JDK1.8的区别(源码解读)

本文详细阐述了JDK1.7和JDK1.8中HashMap的区别,包括存储结构、初始化方式、插入数据方式、hash值计算、扩容策略等方面的变化。JDK1.8引入了红黑树,优化了插入和查找效率,同时在扩容策略上进行了优化,避免了多线程环境下的一些问题。此外,还解析了put和get方法的源码,解释了HashMap的常见问题及其解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

HashMap在JDK1.7和JDK1.8的区别

一.区别

  1. 存储结构不同:JDK1.7是数组+链表,JDK1.8则是数组+链表+红黑树结构;
  2. 初始化方式不同:JDK1.7中当哈希表为空时,会先调用inflateTable()初始化一个数组;而JDK1.8则是直接调用resize()扩容;
  3. 插入数据方式不同:插入键值对的put方法的区别,JDK1.8中会将节点插入到链表尾部,而JDK1.7中是采用头插,因为JDK1.7是用单链表进行的纵向延伸,当采用头插法时会容易出现逆序且环形链表死循环问题。但是在JDK1.8之后是因为加入了红黑树使用尾插法,能够避免出现逆序且链表死循环的问题。;
  4. hash值计算不同:JDK1.7采用9次扰动(4次位运算+5次异或运算),JDK1.8采用2次扰动(1次位运算+1次异或运算)
  5. 扩容时JDK1.8会保持原链表的顺序,而JDK1.7会颠倒链表的顺序;而且JDK1.8是在元素插入后检测是否需要扩容,JDK1.7则是在元素插入前;
  6. 扩容后数据存储位置的计算方式不同:1. 在JDK1.7的时候是直接用hash值和需要扩容的二进制数进行&(这里就是为什么扩容的时候为啥一定必须是2的多少次幂的原因所在,因为如果只有2的n次幂的情况时最后一位二进制数才一定是1,这样能最大程度减少hash碰撞)(hash值 & length-1)
  7. 扩容策略不同:JDK1.7中是只要不小于阈值就直接扩容2倍;而JDK1.8的扩容策略会更优化,当数组容量未达到64时,以2倍进行扩容,超过64之后若桶中元素个数大于6就将链表转换为红黑树,但如果红黑树中的元素个数小于6就会还原为链表,当红黑树中元素不小于32的时候才会再次扩容。

二.JDK1.8put、get方法源码解读

HashMap是基于hashing的原理,我们使用put(key, value)存储对象到HashMap中,使用get(key)从HashMap中获取对象。
1)put方法,直接调用putVal:

   public V put(K key, V value) {
   
        return putVal(hash(key), key, value, false, true);
    }

putVal方法:

    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
   
        //定义存放元素的节点数组,节点,变量n,i;
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        /*
            步骤1:判断table是否为空
            1)table 表示存储在Map中的元素的数组
            2)(tab = table) == null 表示将table赋值给tab,并且判断tab是否为null。
            3)(n = tab.length) == 0 表示,将tab的长度赋值给n,并判断n 是否等于-
         */
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        // 步骤2:计算index,并对null做处理
        
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值