关于HashMap中的位运算

关于HashMap中的位运算

为什么HashMap的数组大小一定是2的倍数?
主要有两点

1、当n为2的整数次幂,hash%n等价(n-1)&hash
这个公式怎么来的呢?

举个10进制的例子!
115%10 = 5;
由于10是十进制的整数次幂
1 1 5
   1 0
——————
      5 (将第二个1之前数都可以整除10(因为10是10的整数幂),所以只剩下5)

100110
  00100
——————
        10 (同样第三个1之前的数可以整除100(因为100【2进制】是2的整数幂)。所以只剩下10)

这时我们怎么可以得到1后面的数呢?
那就是&运算
100110
000011
————
        10 (这与上面的公式是等价的,这就是hash%n等价(n-1)&hash由来)

第二个好处就是扩容时,节点可能需要重新分到不同的桶值时避免了重新计算桶值。
也就是计算(n-1)&hash

为什么呢?
前面说到容量必须2的整数次幂,通过看源码我们知道扩容一次增加2倍,也就是n<<1
100110
000100
————
        10 没扩容前

100110
001000
————
        10 扩容后
斜体样式扩容后的取余结果比原来的结果多往前加了一位
     100110
原来:  10
扩容:110

(原来第三位如果是0)扩容前后余数不变,(原来第三位是1)扩容后的余数等于扩容前的余数+扩容前容量

我看了很多博客都说是容量是2的n次幂,可以使得添加的元素均匀分布在HashMap中的数组上,减少hash碰撞。

我的理解是
只要计算桶值公式为hash%n,无论n取什么值,它都是均匀分布的。
只是说当n为2的整数次幂时hash%n等价(n-1)&hash这才使的它可以均匀分布。

再啰嗦一点:为什么hashMap.hash()方法需要高低位异或。

static final int hash(Object key) {
  	int h;
  	//map的key可以为null因为hash值为0
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

上文说到取余公式(n-1)&hash的由来。余数就等于截取原来hash的后几位。
假设们不高低位异或。可能会出现某些key之间的hash值,只有高位不同,那么我们所求的余数就会是相同的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值