HashMap在1.7和1.8的区别

前言

在 Java 中,HashMap 是一种非常常用的数据结构。它是一个键值对存储的容器,能够快速地插入、查找和删除元素。但是,在不同的 Java 版本中,HashMap 的实现可能有所不同,这也会导致它在不同环境下的性能表现和行为也有所不同。本文将主要讨论 HashMap 在 Java 1.7 和 1.8 中的区别,帮助读者更好地理解这两个版本中 HashMap 的特性和优化。

数据结构

在 Java 1.7 中,HashMap 的底层数据结构是数组+单向链表。具体来讲,它是将所有的键值对存储在一个 Entry 数组中,每个 Entry 包含一个指向下一个 Entry 的指针,因此多个 Entry 以链表的形式存在,当哈希冲突时,新的 Entry 会插入到链表的末尾。

在 Java 1.8 中,HashMap 的底层数据结构是数组+链表/红黑树,其实就是在 Java 1.7 的基础上,新增了一种结构:红黑树。当链表长度达到阈值(默认为8)时,链表就会转换成红黑树。这样做的好处是,在查找、插入、删除较多的情况下,红黑树的性能比链表更好。

那么,为什么 Java 1.8 中要采用链表和红黑树两种数据结构呢?一方面,链表对于小规模数据操作比较快;另一方面,红黑树对于大规模数据操作表现更好。因此,在 Java 1.8 中,HashMap 会自适应地根据数据规模来选择合适的数据结构。

扩容机制

HashMap 在元素过多的情况下,会扩容数组以缓解压力。不同的版本中 HashMap 的扩容机制也有所不同。

在 Java 1.7 中,HashMap 的扩容机制是在原数组的基础上,重新创建一个更大的数组,然后将原数组中的元素逐个添加地新数组中。这个过程比较耗费时间和性能。

在 Java 1.8 中,HashMap 的扩容机制发生了变化。首先,它会计算出(容量*负载因子)的值,如果当前超过这个值,就会触发扩容。此时,它会创建一个大小为原数组两倍的新数组,并将原来的数据迁移到新数组中。这个过程相比 Java 1.7 中的扩容机制更快、更节省空间。

此外,在 Java 1.8 中,如果旧链表中的元素个数小于 8,而且整个 HashMap 的元素个数大于 64,就不会转成红黑树了,这样可以避免过度消耗空间。

添加元素

HashMap 在添加元素时,如果位置已经有元素,则需要进行替换或者插入操作。不同版本中 HashMap 的实现也有所不同。

在 Java 1.7 中,HashMap 的添加元素方式比较简单。如果数组中该元素位置为空,则直接插入元素;如果已有元素,则遍历链表进行插入。

在 Java 1.8 中,当使用链表时,添加元素的方式与 Java 1.7 相同。但是,当链表长度达到阈值(默认为8)时,链表会转成红黑树。在红黑树中添加元素的方式与在链表中插入元素的方式有所不同。

具体来说,如果当前节点是链表节点,则会执行和 Java 1.7 相同的插入逻辑;如果当前节点是红黑树节点,则使用红黑树的方式插入。这样做的好处是,在查找、插入和删除较多的情况下,红黑树的性能要比链表的性能更好。

获取元素

HashMap 在获取元素时需要进行查找。不同版本中 HashMap 查找元素的过程也有所不同。

在 Java 1.7 中,HashMap 查找元素的方式是先通过 hash 值找到对应的数组下标,然后再从链表中顺序查找。

在 Java 1.8 中,查找元素的方式也是先通过 hash 值找到对应的数组下标。如果该位置是链表节点,则按照链表的方式顺序查找;如果该位置是红黑树节点,则使用红黑树的查找方式。根据实验结果,当元素数量不是很大时,链表的查找性能优于红黑树,因为红黑树需要进行比较和旋转等操作,会有一定的性能损耗。

你可能感兴趣的:(链表,数据结构,java)