java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java 8 HashMap原理

Java 8中HashMap的底层原理解析

作者:zhuhai0613

HashMap作为Java中常用的数据结构之一,在JDK 1.8中经过了一系列的优化和改进,深入理解其底层原理,包括哈希算法、数组与链表结构、红黑树的引入等,有助于更好地使用和理解HashMap的性能特性,这篇文章主要介绍了Java 8中HashMap的底层原理,需要的朋友可以参考下

引言

HashMap是Java中常用的集合类,用于存储键值对。其底层实现经过多次优化,包括哈希算法、数组扩容、链表转红黑树等。本文将深入研究HashMap的底层原理,并详细探讨如何解决哈希碰撞的技术。

1. 哈希算法

HashMap的核心是哈希算法,它通过将键的哈希码映射到数组索引,实现快速的数据查找和插入。在JDK 1.8中,哈希算法经过了一些优化,以提高均匀性和减少碰撞的可能性。

2. 数组与链表结构

HashMap的底层数据结构是一个数组,每个数组元素是一个链表(或红黑树)。当多个键映射到相同的索引位置时,它们将被存储在同一个链表中。为了解决哈希碰撞,链表中存储的是一个个键值对。

3. 键值对的存储

HashMap中,键值对以Node对象的形式存储。每个Node包含键、值、哈希码以及指向下一个Node的引用。当产生哈希冲突时,新的Node将被添加到链表的末尾。

4. 解决哈希碰撞的方法

链地址法:当发生哈希冲突时,将冲突的元素以链表的形式链接在一起,同一个链表上的元素哈希值相同。

红黑树:当链表长度超过一定阈值(默认为8)时,链表会转换为红黑树,可以减少查找时间。因为红黑树的时间复杂度为O(logn),而链表为O(n)。

扩容rehash:当HashMap中的元素数量太多,超过数组大小*加载因子时,会发生扩容。扩容后,需要对原数组中的所有元素重新计算哈希值,然后放到新的扩容后的数组中,这样可以增加链表长度,减少哈希冲突。

优化哈希算法:JDK 1.8中优化了哈希算法,通过hashCode()的高16位异或低16位实现的:(h = k.hashCode()) ^ (h >>> 16),提高了哈希碰撞分布性。

所以Java 8中HashMap主要通过链地址法+红黑树+扩容rehash+优化哈希算法来解决哈希冲突。这些方法相结合可以有效地解决哈希冲突问题,提高HashMap的性能。

5. 数组扩容机制

HashMap中的元素数量超过容量乘以加载因子时,数组会被扩容。在JDK 1.8中,默认加载因子是0.75。扩容涉及到重新计算哈希码、重新分配数组,并将现有元素重新放置到新的数组中。这确保了HashMap的性能和空间的平衡。

6. 红黑树的引入

为了应对链表过长的情况,JDK 1.8引入了红黑树。当链表长度达到8时,链表将被转换为红黑树,以提高查找效率。红黑树的引入使得在最坏情况下,查找时间复杂度从O(n)降低到O(log n)。

为什么当链表长度达到8时,链表将被转换为红黑树,又为什么红黑树转链表的阈值为6?
首先和hashcode碰撞次数的泊松分布有关,主要是为了实现时间和空间的平衡,在负载因子为0.75默认情况下,单个hash槽内元素个数为8的概率小于百万分之一,将7作为一个分水岭,等于7时不做转换,大于等于8才转红黑树,小于等于6才转链表,链表中元素个数为8时的概率已经非常小,再多的就更少了,所以原作者在选择链表元素个数时选择了8,是根据概率统计而选择的,红黑树中的TreeNode,是链表中的Node所占空间的2倍,虽然红黑树的查找效率为o(logN),要优于链表的o(N),但是当链表长度比较小的时候,即使全部遍历,时间复杂度也不会太高,所以,要寻找一种时间和空间的平衡,即在链表长度达到一个阈值,之后再转换为红黑树,之所以是8,是因为Java的源码贡献者,在进行大量实验发现,hash碰撞发生8次的概率,已经降低到了0.00000006,几乎为不可能事件,如果真的碰撞发生了8次,那么这个时候说明由于元素,本身和hash函数的原因,此次操作的hash碰撞的可能性非常大了,后序可能还会继续发生hash碰撞,所以,这个时候,就应该将链表转换为红黑树了,也就是为什么链表转红黑树的阈值是8;
最后,红黑树转链表的阈值为6,主要是因为:如果也将该阈值设置于8,那么当hash碰撞在8时,会反生链表和红黑树的不停相互激荡转换,白白浪费资源。

7. 在Java 8中的实现细节

在JDK 1.8中,HashMap的实现经过了优化,包括更好的哈希算法、红黑树的引入、链表长度的控制等。这些变化使得HashMap在面对各种情况时都能提供高效的性能。

8. 性能优化与注意事项

在使用HashMap时,需要注意一些性能优化的问题,例如合理选择初始容量和加载因子、避免频繁扩容等。对于特定的应用场景,可以通过调整这些参数来达到更好的性能。

结论

HashMap作为Java中常用的数据结构之一,在JDK 1.8中经过了一系列的优化和改进。深入理解其底层原理,包括哈希算法、数组与链表结构、红黑树的引入等,以及如何解决哈希碰撞的技术,有助于更好地使用和理解HashMap的性能特性。在实际应用中,根据具体场景选择适当的参数,可以更好地发挥HashMap的优势,提高程序的性能和效率。

到此这篇关于Java 8中HashMap的底层原理的文章就介绍到这了,更多相关Java 8 HashMap原理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文