hash hashcode变化_谈谈HashMap的hash()方法巧妙之处

笔者个人理解,不正之处,欢迎指正与讨论。

先看看JDK1.8中hash算法的实现,感觉真的很巧妙。

static final int hash(Object key) {

int h;

return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);

}

index = (n - 1) & hash(key) //n表示长度

如果是自己实现hash算法的话,最简单的话就是直接用hasCode对取余

index = key.hasCode() % n

在HashMap的实现中要求n的长度为2的n次幂

对于2的n次幂取余,可以用更加高效的方法

index = key.hasCode() & (n-1)

上面两种方法都存在一种缺陷,就是取余的计算结果对高位是无效的,只是对低位有效,当计算出来的hasCode()只有高位有变化时,取余的结果还是一样的。

例如

int hashCode1 = 01110101

int hasdCode2 = 01010101

int index1 = 01110101 & 1111 -> 0101

int index2 - 01010101 & 1111 -> 0101

//十进制翻译

int hashCode1 = 117

int hashCode2 = 85

int index1 = 117 % 16 -> 5

int index2 = 85 % 16 -> 5

从上面的例子可以看出来,当key计算出来的hashCode()只有高位变化时,最终算出来的index索引就会引起hash冲突,如果冲突太多的话,HashMap的效率就会非常低下了。

static final int hash(Object key) {

int h;

return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);

}

再来看看这段代码,对key的hashCode值进行再一次计算。在java中,hashCode是32位的。

首先,对hashCode进行16位的无符号右移。

(我们的例子就假设hashCode是8位的)

int hashCode1 = 01110101 >>> 4

--> hashCode1 = 00000111

int hasCode2 = 01010101 >>> 4

-->hasCode2 = 00000101

然后,对自身进行与或运算。

hashCode1 = 01110101 ^ 00000111

--> hashCode1 = 01110010

hashCode2 = 01010101 ^ 00000101

--> hashCode2 = 01010000

最后,取余

hashCode1 = 01110010 & 1111 = 0010

hashCode2 = 01010000 & 1111 = 0000

通过上面的分析,hash的再次计算能够把高位的变化影响到了低位的变化,真的很神奇啊

一句神奇的代码,大大减少了hash冲突,牛逼!

不正之处,欢迎指正。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值