HashMap 容量为2次幂的原因




一、什么是HashMap?

HashMap是Java中的集合类,是存放键值对形式的数据(Key和Value),例如QQ账号和QQ密码,QQ账号就是Key而密码则是Value
详细可以看这两篇上 HashMap源码剖析(上)——java集合
和下 HashMap源码剖析(下)——java集合

二、为什么扩容2的n次幂?

首先先看一下HashMap中的putVal方法(存值的)和resize方法(扩容的),之所以HashMap扩容是2的n次幂和这两个方法有千丝万缕的联系。

通过putVal方法可以看出来HashMap在存值时会先把key的hash值和扩容后的长度进行一次按位与运算,其中hash是在hash方法中把key进行计算后的出来的结果,n是扩容的长度(也就是数组的长度,默认为16),然后判断是否hash碰撞在进行不同的存储。
在这里插入图片描述
通过resize方法可以看出来扩容时会新建一个tab,然后遍历旧的tab,将旧的元素进行e.hash & (newCap - 1)的计算添加进新的tab中,也就是(n - 1) & hash的计算方法,其中n是集合的容量,hash是添加的元素经过hash函数计算出来的hash值。
在这里插入图片描述
之所以这样2n扩容和上面的两个方法有极大的关系,首先他们都使用了按位与运算,按位与运算就是把值先变成二进制然后进行运算,如果有0则为0,都为1时则输出为1,HashMap默认容量为16那么在存放到数组时就是n-1也就是15,而15二进制则是1111扩容后为32-1及11111111

,如果都为1的情况下是可以极大的减少hash碰撞,增加效率的。

通过下面例子来看一下当容量为11111111时按位与运算的结果,通过下面的结果可以看出来结果很分散,大大减少了hash碰撞的发生。
在这里插入图片描述
再看一下当容量不为11111111而是为其他值的时候,通过下面的结果可以看出,1、2、4跟不同的值进行hash运算但是结果却是相同的,也就是发生了hash碰撞。

在这里插入图片描述

同时 确定数组位置的实现是 i=(n-1)& hash,其中 n 代表数组的长度,即map的容量。

当n为2的幂次方时,(n-1)& hash 的值是均匀分布的,我们假设n=16,hash从0开始递增:
在这里插入图片描述
当n不为2的幂次方时,(n-1)& hash 的值不是是均匀分布的,我们假设n=15,hash从0开始递增:
在这里插入图片描述
由上面可以看出,当我们根据key的hash确定其在数组的位置时,如果n为2的幂次方,可以保证数据的均匀插入,如果n不是2的幂次方,可能数组的一些位置永远不会插入数据,浪费数组的空间,加大hash冲突。
另一方面,一般我们可能会想通过 % 求余来确定位置,这样也可以,只不过性能不如 & 运算。而且当n是2的幂次方时:hash & (length - 1) == hash % length

因此,HashMap 容量为2次幂的原因,就是为了数据的的均匀分布,减少hash冲突,毕竟hash冲突越大,代表数组中一个链的长度越大,这样的话会降低hashmap的性能。

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

依嘫_吃代码

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

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

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

打赏作者

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

抵扣说明:

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

余额充值