HashMap 在扩容时为什么通过位运算 (e.hash & oldCap) 得到新数组下标


分析
  • HashMap在扩容时会把 Node 桶中的元素拆分成两个链表或者红黑树 (分别对应桶为链表或红黑树), - JDK1.8 扩容流程,然后根据位运算来判断 Node 桶中的结点插入两个中的哪一个。(下文中会用 low,high表示)
  • 扩容时执行的 resize( ) 方法中的源码,把当前结点插入到 low 还是 high 的判断条件是 (e.hash & oldCap) == 0,那到底这个 & 运算的意义何在呢?
  • 首先我们知道 HashMap 计算 key 所对应数组下标的公式是 (length - 1) & hash,其中 length 是数组长度,hash 是 hash值,这个公式等价于 hash % length (当 length 是 2 的 n 次幂时) 。
  • 从下图中我们可以看出,hash % length 的结果只取决于小于数组长度的部分,这个 key 的 hash 值的低四位就是当前所在数组的下标。扩容后 新数组长度 = 旧数组长度 * 2,也就是左移 1 位,而此时 hash % length 的结果只取决于 hash 值的低五位,前后两者之间的差别就差在了第五位上。
    在这里插入图片描述

  • 如果第五位是 0,那么只
HashMap采用两倍扩容的原因有几个方面的考虑。首先,HashMap数组大小一定要是2的幂,这是因为HashMap使用了位运算来计算元素的下标。在HashMap的内部实现中,计算元素下标使用的是`(n - 1) & hash`的位运算操作,其中n代表数组的大小,hash代表元素的哈希值。由于位运算的特性,数组大小如果是2的幂,可以保证计算出的下标均匀分布,减少哈希碰撞的概率。这样可以提高HashMap的查找性能。 其次,采用两倍扩容可以使元素更均匀地散布在HashMap中,进一步减少哈希碰撞的可能性。当HashMap的负载因子超过一定阈值,即填入元素的个数除以数组大小的比例超过了负载因子阈值,就会触发扩容操作。扩容操作会创建一个的更大的数组,并将原来数组中的元素重计算哈希值后插入到数组中。采用两倍扩容可以保持元素原本的相对位置关系,不会过分打乱元素的散布情况。 最后,HashMap扩容操作是一个相对耗的操作,因为需要重计算所有元素的哈希值并插入到数组中。为了减少扩容的次数,采用两倍扩容可以在一定程度上降低扩容的频率,提高HashMap的性能。当HashMap的元素数量逐渐增多数组的大小也会跟着增大,这样可以减少扩容操作的次数,提高HashMap的效率。 综上所述,HashMap采用两倍扩容可以保证元素的均匀散布、减少哈希碰撞的发生,并且可以在一定程度上提高HashMap的性能。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值