Java基础(9)jdk1.8对HashMap的优化

Java 8为HashMap带来了显著的性能优化,主要体现在以下几个方面:

  1. 引入红黑树: 当链表长度超过一定阈值(默认为8)时,链表会转换成红黑树,以减少查找时间。
  2. 优化哈希碰撞的处理: 通过结合高位和低位的哈希值,减少碰撞。
  3. 优化扩容操作: 在扩容时,元素的位置要么在原位置,要么在原位置加上旧容量的位置,这减少了重新计算哈希值的需求。

红黑树引入

在JDK 8之前,HashMap中解决哈希冲突的唯一方法是链表。但是,当哈希表变得非常大时,如果哈希函数不够好,或者数据分布不均匀,链表可能会变得很长,这会导致查找效率降低至O(n)。JDK 8引入了红黑树结构来优化这一点,当链表长度超过阈值时,链表会转换成红黑树,此时查找的时间复杂度能降低到O(log n)。

final void treeifyBin(Node<K,V>[] tab, int hash) {
    int n, index; Node<K,V> e;
    if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
        resize();
    else if ((e = tab[index = (n - 1) & hash]) != null) {
        TreeNode<K,V> hd = null, tl = null;
        do {
            TreeNode<K,V> p = replacementTreeNode(e, null);
            if (tl == null)
                hd = p;
            else {
                p.prev = tl;
                tl.next = p;
            }
            tl = p;
        } while ((e = e.next) != null);
        if ((tab[index] = hd) != null)
            hd.treeify(tab);
    }
}

哈希值的优化

JDK 8对哈希值的计算方式也做了优化,通过将高位参与运算,减少碰撞。

static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

此处,hashCode()的高16位通过与低16位进行异或运算,加入了更多的随机性,减少了哈希碰撞。

扩容的优化

在JDK 8中,HashMap的扩容逻辑也得到了优化。扩容时,元素要么保持在原索引位置,要么移动到原索引位置加上旧容量的位置。这种方法避免了重新计算哈希值。

Node<K,V> loHead = null, loTail = null;
Node<K,V> hiHead = null, hiTail = null;
Node<K,V> next;
do {
    next = e.next;
    if ((e.hash & oldCap) == 0) {
        if (loTail == null)
            loHead = e;
        else
            loTail.next = e;
        loTail = e;
    } else {
        if (hiTail == null)
            hiHead = e;
        else
            hiTail.next = e;
        hiTail = e;
    }
} while ((e = next) != null);

这段代码显示,在扩容过程中,通过判断(e.hash & oldCap) == 0来决定元素是保留在原位置,还是移动到新的位置(原位置+旧容量)。这大大减少了扩容时的计算量。

这些优化显著提高了HashMap在不同场景下的性能,尤其是在处理大量数据时。通过使用红黑树减少查找时间,优化哈希值的计算以减少碰撞,以及提高扩容效率,JDK 8的HashMap成为了一个更加强大和高效的数据结构。

  • 19
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
HashMapJava中常用的数据结构之一,它基于哈希表实现。在JDK 1.8中,HashMap的底层实现主要包括数组和链表(或红黑树)两部分。 首先,HashMap内部维护了一个Entry数组,每个Entry对象包含了键值对的信息,包括键、值和指向下一个Entry的指针。数组的长度是固定的,但可以根据需要进行扩容。 当我们向HashMap中插入一个键值对时,首先会根据键的hashCode()方法计算出一个哈希值。然后,通过哈希值与数组长度取模的方式确定该键值对在数组中的位置。如果该位置上已经存在其他键值对,就会发生冲突。 解决冲突的方法是使用链表或红黑树。在JDK 1.8中,当链表长度超过一定阈值(默认为8)时,链表会转换为红黑树,以提高查找效率。这样,在插入、删除和查找操作时,可以通过哈希值快速定位到对应的链表或红黑树,然后再在链表或红黑树中进行操作。 当我们需要查找一个键对应的值时,HashMap会根据键的哈希值找到对应的位置,然后遍历链表或红黑树来找到具体的键值对。 需要注意的是,HashMap并不保证元素的顺序,即插入和遍历的顺序不一定相同。如果需要有序的集合,可以考虑使用LinkedHashMap。 总结一下,JDK 1.8中HashMap的底层原理主要是通过数组和链表(或红黑树)来实现,通过哈希值快速定位到对应的位置,然后在链表或红黑树中进行操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

辞暮尔尔-烟火年年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值