底层了解JDK1.7和JDK1.8的HashMap区别

HashMap底层解析1.8新特性

HashMap的底层是数组+链表形式(1.7版本)
HashMap的底层数组+链表+红黑树(1.8版本)
  以上一点是最主要的不同点
那么1.7和1.8的一些共同属性是:
   数组的默认长度:16;
   负载因子:0.75
   扩容倍数:2倍
   阈值(也就是什么时候需要扩容):16*0.75=12

 
在这里插入图片描述
由于底层的源码以及方法太多,博主值选择put()方法进行详解

HashMap<String,String> myhashMap = new HashMap<String,String>();
myhashMap.put("水果","柚子");
//另外提一下,put()方法是有返回值的,当key值相同时,返回值为之前的value值
//key值不同时,返回null;即插入的值是否会覆盖原元素
System.out.println(myhashMap.put("水果","橘子"));
//这里覆盖了原元素,将打印出 "柚子"

这边查看put()方法的源码,发现调用了hash()方法计算出插入元素key值的hash值,然后通过hashCode()获取的值对数组长度-1 进行&运算,然后通过一系列的位运算来获得这个Key值在数组中的存储位置。
在这里插入图片描述
当然这边给出的是JDK1.8的源码,1.7的源码的算法不太一样。
1.为什么要进行如此复杂的位运算?
  这边先说一下,当两个Hash值相同时,也就是在数组上的存储位置相同时(对象不一致),也就是所谓的hash碰撞,那么HashMap会将新的元素以链表的形式连接在那个数组的位置;所以,为了减少链表的长度,就需要复杂的算法来减少hash碰撞,这样就可以减少链表的长度。
  
  
既然说到了链表,那么来聊一下1.7版本的链表插入形式
  在JDK1.7版本的时候,当产生了hash碰撞,后来的元素,也就是新元素是插入到链表的头部,因为插入链表的头部对于插入操作来说效率是最高的,那么问题就来了,插入了头部,又是单链表,要怎么查询新的元素呢?
  其实在1.7中,插入链表头部之后还会进行一步操作,就是将此时的链表头部赋值给在数组中元素,那么就变成了链表的头是数组元素,数组中之前的元素就是链表的下一个元素,就可以进行查询了;
  
  
此时就可以说一下1.8的插入形式
  1.8的HashMap多了一个红黑树,这里有一个属性
在这里插入图片描述
  这个属性是为了确定什么时候将链表变为红黑树的,类似与阈值;
  当一个链表长度达到8时,将转换为红黑树,这是发生hash碰撞时的第一个不同点;
  第二个不同点就是:1.7插入我们说过是插入链表头部,但是1.8是插入到尾部。
 
看一下源码:
在这里插入图片描述
1.8之后也顺便将Entry改名为Node,从代码中可以看出,在插入一个节点(Node)时,他的next值设为了null,也就是说它是最后一个节点。 tab[i] = newNode(hash, key, value, null);
  
  
插入说完了 来说一下扩容:
  1.7和1.8都会扩容,扩容都是以2倍扩容
  那么来说一下扩容的前提:
   1.7的扩容条件有两个,1.数组元素到达阈值,且新来的元素插入的位置有元素占着,很少有人会知道第二个条件,举个例子:
   比如数组长度16,现在下标为1234还空着,那么,此时新来的元素要是hash值算出的位置是在1234中,那么就不会进行扩容,只有hash冲突了才会扩容。且扩容完之后,所有的元素的hash值都要重新计算,所以在扩容过程中可能产生死锁。
  1.8则摒弃了第二个条件,只要数组使用了12个位置就进行扩容,之前元素的位置不会发生改变

总结

JDK7
HashMap底层是数组加链表的形式
数组的默认长度为16,加载因子为0.75,也就是16*0.75=12(阈值)
当计算出元素的位置在数组中冲突时,那么会以链表的形式存储新的元素,新的元素插在链表的头部,然后将链表下移,也就是将数组中的值赋值给新来的元素,
当数组中12个位置被占据时(也就是达到了阈值),同时新插入的元素的插入位置不为空,就会进行扩容 2倍扩容,
扩容完之后重新计算所有元素的hash值,(会产生死锁)

JDK8
HashMap底层是数组加链表加红黑树
数组的默认长度为16,加载因子为0.75,也就是16*0.75=12(阈值)
当计算出元素在数组中的位置相同时,则生成链表,并将新的元素插入到尾部,假如链表上元素超过了8个,那么链表将被改为红黑树,同时也提高了增删查效率
当数组元素个数达到了阈值,那么此时不需要判断新的元素的位置是否为空,数组都会扩容,2倍扩容
扩容完之后,之前的元素位置不会发生改变,也就不会产生死锁

Node为链表的节点,有next和prev两个指针,分别指向后一个和前一个

插入链表的顺序不同
链表会转变为红黑树
hash算法简化
resize(扩容)的逻辑修改(jdk7会出现死锁,jdk8不会)
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值