Java中HashMap的工作原理

 介绍

HashMap是Java中最常用的数据结构之一,它实现了Map接口,用于存储键值对。

在JDK1.8之前,HashMap使用的是数组和链表的组合来实现。数组被分成一个个称为桶(bucket)的单元,每个桶可以存储多个键值对。当我们向HashMap中put一个键值对时,首先会根据键的hashcode值计算出对应的桶的索引位置,然后将该键值对存储在该桶中。

如果多个键值对计算得到的桶索引相同,则会以链表的方式存储在同一个桶中。链表中的每个节点都包含一个键值对,并且通过比较键的equals方法来判断键是否相等。当我们根据键获取值时,HashMap会遍历链表,找到匹配的键值对。

然而,由于HashMap使用链表来处理冲突,当存储大量键值对时,链表的长度会越来越长,导致查找效率降低,即时间复杂度变为O(n)。此外,由于链表无序,查找效率更低。这也是为什么在JDK1.8之前的HashMap在处理大量数据时性能较差的原因。

为了解决这个问题,JDK1.8中对HashMap进行了优化,引入了红黑树的概念。当链表长度超过阈值(默认为8)时,链表会自动转化为红黑树,从而加快查找速度。红黑树是一种平衡二叉搜索树,具有较高的查找效率。

因此,在JDK1.8之后的HashMap中,当链表长度超过阈值时,由链表转换为红黑树,大大提高了HashMap的性能。此外,JDK1.8还对HashMap的实现进行了一系列的优化,如使用位运算代替取余操作来计算桶的索引,提高了速度和效率。

总结起来,JDK1.8之前的HashMap使用数组和链表的组合来实现,处理大量数据时性能较差。而JDK1.8之后的HashMap引入了红黑树的概念,提高了查找效率,使其更加适合存储和操作大量数据。

存入数据时

  1. 首先,根据键的哈希码(hash code)通过哈希函数(hash function)计算出键的索引(index)。哈希函数将哈希码映射到哈希表的槽位(bucket)上。

  2. 如果槽位是空的,直接将键值对存储在该槽位上。

  3. 如果槽位已经有其他键值对,可能发生哈希碰撞(hash collision),即两个键具有相同的哈希码。解决哈希碰撞的方法有多种,最常用的是链地址法(chaining),即在槽位上维护一个链表,将发生碰撞的键值对串联起来。

  4. 当链表长度超过一定阈值(如8)时,可以考虑将链表转换为树结构,以提高查找效率。转换为树的过程如下:

    a. 创建一个根节点,将原链表的第一个键值对作为根节点的元素。

    b. 遍历链表中的每个键值对,将其插入到树中的正确位置上。

    c. 在插入过程中,根据键的比较结果,将键值对插入到树的左子树或右子树中。

    d. 当树的大小达到一定阈值(如6)时,将树平衡化以维持树的性能。

在哈希表中转换链表为树的过程,可以提高查找效率,特别是在槽位上的键值对数量较多时。

获取数据时

 

当我们要获取 HashMap 中的数据时,它首先使用 key 的哈希值来确定数据在数组中的索引位置。然后,它会在该索引位置上的链表中遍历,直到找到对应的 key。具体的流程如下:

  1. 首先,HashMap 根据 key 的哈希值计算出存储位置(在数组中的索引)。
  2. 如果该位置上的链表为空,则说明没有找到对应的数据,返回 null。
  3. 如果该位置上的链表不为空,则遍历链表中的每个节点。
  4. 对比每个节点的 key 和目标 key 是否相等,如果相等,则找到了对应的数据,返回该节点的值。
  5. 如果遍历完整个链表都没有找到对应的数据,则说明 HashMap 中不存在该 key,返回 null。

总结起来,HashMap 的获取数据流程主要是根据 key 的哈希值确定数据在数组中的位置,然后在该位置上的链表(或红黑树)中遍历查找对应的数据。 

hashmap的扩容机制

 

HashMap的扩容机制是指当HashMap中的元素个数超过了负载因子(load factor)乘以当前容量时,就会触发扩容操作。

负载因子是一个介于0和1之间的值,表示HashMap在容量自动扩容之前可以达到的填充因子的比例。当HashMap中的元素个数超过负载因子乘以当前容量时,就会触发扩容操作。

扩容操作会创建一个新的更大的数组,然后将原来数组中的元素重新计算哈希值,并放入新的数组对应的位置中。这个过程称为重新哈希(rehashing)。

在扩容的过程中,HashMap会将元素重新分布到新的数组中,这有可能导致一些元素的哈希冲突,即多个元素映射到了同一个位置上。为了解决哈希冲突,HashMap使用了链表的方式来存储相同位置的元素。当元素被重新分配到新数组的相同位置时,它会被添加到链表的末尾。

为了优化性能,当链表的长度超过一定阈值(8)时,链表会转化成红黑树。这样可以在查找、插入和删除元素时,减少平均时间复杂度。

通过扩容操作,HashMap可以保持一个较低的填充因子,从而提高查询和插入操作的性能。

需要注意的是,扩容操作是一个比较耗时的操作,因为需要重新计算哈希值和重新分配元素。所以,在使用HashMap时,我们应该尽量预估元素的个数,并设置合适的初始容量和负载因子,以减少扩容的频率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值