其他分享
首页 > 其他分享> > HashMap的数据结构(1.7与1.8的区别)

HashMap的数据结构(1.7与1.8的区别)

作者:互联网

HashMap的数据结构

HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。

基本限制

数组默认长度:1<<4 即 16

数组最大值 :1<<30

默认加载因子:0.75 ------ 数组容量*0.75 = 12 (使用大小触发点:使用到12时做扩大数组容量的操作)

链表变形为红黑树的触发大小:8 -------- 注:变形目的是降低查找的时间复杂度。

红黑树变形为链表的触发大小:6

哈希冲突

如果两个不同的元素,通过哈希函数得出的实际存储地址相同怎么办?

也就是说,当我们对某个元素进行哈希预算,得到一个存储位置,然后进行插入时,发现已经被其他元素占用了(其实这就是所谓的hash冲突,也叫哈希碰撞,哈希函数的设计至关重要,好的哈希函数会尽可能的保证计算简单和散列地址分布均匀,但是我们需要清楚的是,数组是一块连续的固定长度的内存空间,再好的哈希函数也不能保证得到的存储地址绝对不发生冲突。那么哈希冲突如何解决呢?哈希冲突的解决方案有多种:开放定址法(发生冲突,继续寻找下一块未被占用的存储地址),再散列函数法,链地址法,而HashMap即是采用了链地址法,也就是数组+链表的方式。)

HashMap的实现原理

HashMap的主干是一个Entry数组。Entry是HashMap的基本组成单元,每一个Entry包含一个key-value键值对。(其实所谓Map其实就是保存了两个对象之间的映射关系的一种集合)

简单来说,HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的,如果定位到的数组位置不含链表(当前entry的next指向null),那么查找,添加等操作很快,仅需一次寻址即可;如果定位到的数组包含链表,对于添加操作,其时间复杂度为O(n),首先遍历链表,存在即覆盖,否则新增;对于查找操作来讲,仍需遍历链表,然后通过key对象的equals方法逐一比对查找。所以,性能考虑,HashMap中的链表出现越少,性能才会越好。

jdk1.7与jdk1.8中HashMap区别

最重要的一点是底层结构不一样,1.7是数组+链表,1.8则是数组+链表+红黑树结构;

jdk1.7中当哈希表为空时,会先调用inflateTable()初始化一个数组;而1.8则是直接调用resize()扩容;

插入键值对的put方法的区别,1.8中会将节点插入到链表尾部,而1.7中是采用头插;

jdk1.7中的hash函数对哈希值的计算直接使用key的hashCode值,而1.8中则是采用key的hashCode异或上key的hashCode进行无符号右移16位的结果,避免了只靠低位数据来计算哈希时导致的冲突,计算结果由高低位结合决定,使元素分布更均匀;

扩容时1.8会保持原链表的顺序,而1.7会颠倒链表的顺序;而且1.8是在元素插入后检测是否需要扩容,1.7则是在元素插入前;

jdk1.8是扩容时通过hash&cap==0将链表分散,无需改变hash值,而1.7是通过更新hashSeed来修改hash值达到分散的目的;

扩容策略:1.7中是只要不小于阈值就直接扩容2倍;而1.8的扩容策略会更优化,当数组容量未达到64时,以2倍进行扩容,超过64之后若桶中元素个数不小于7就将链表转换为红黑树,但如果红黑树中的元素个数小于6就会还原为链表,当红黑树中元素不小于32的时候才会再次扩容。

标签:1.7,HashMap,1.8,链表,数组,哈希
来源: https://www.cnblogs.com/lpzjava/p/16459242.html