JDK1.7,HashMap采用位桶+链表。
而JDK1.8中,HashMap采用位桶+链表+红黑树实现,
hashMap的底层数据存储结构。hashMap实际上是一个数组,每个元素是一个链表即Node<K, V>。元素包括key和value,都是泛型的。还有一个指向下一个node的指针,这就构成了一个链表
1table为空的时候,就给这个table初始化,也就是resize。这里大致说说这个resize,如果table为空,就将table初始化为一个长度为16的,负载因子为0.75的数组。一旦数组中的元素超过门限值(HashMap的当前长度>初始容量*0.75),就会重新resize。初始化为之前table长度的两倍。
Resize步骤
1.扩容:创建一个新的Entry空数组,长度是原数组的2倍。
2.ReHash:遍历原Entry数组,把所有的Entry重新Hash到新数组。为什么要重新Hash呢?因为长度扩大以后,Hash的规则也随之改变。
hash公式:index = HashCode(Key) & (Length - 1)
2当<k,v>的数据将要存进HashMap中的时候,即put时,会先,把k值经过hash函数进行计算得到hash值,再通过hash值进行计算得到数据在数组的下标,当两次的计算index相同,这就是hash冲突。用链表去解决。
Key一样,但是两次的需要存进去的value值是不同的,这就出现了同一个数组后面有一条链表,会比较链表上的每一个value值与当前的value是否相同,若是不相同,通过头插法,将数值插入链表中。
当链表长度超过阈值(8),时,将链表转换为红黑树。红黑树是二分查找,提高了查询的效率。
3
在并发的情况,发生扩容时,可能会产生循环链表,在执行get的时候,会触发死循环,引起CPU的100%问题,所以一定要避免在并发环境下使用HashMap,并发环境下要使用ConcurrentHashmap。
参考:
链接