Hashmap源码什么要对hashcode做一次高16位异或低16位的操作

image

翻译一下就是:计算键的hashCode()方法,并将其高几位通过异或操作传播到低位。因为哈希表使用二的幂次方进行掩码操作,那些仅在当前掩码位之上不同的哈希集将会一直发生冲突。(已知的例子包括在小表中保存连续整数的Float键集。)因此,我们应用了一种变换来将高位的影响向下传播。在速度、实用性和位传播的质量之间存在一种权衡。因为许多常见的哈希集已经相当合理地分布(因此不会从传播中受益),并且因为我们使用树来处理大的冲突集合,我们只是以最便宜的方式异或一些移位的位,以减少系统性的损耗,并且还要结合那些由于表界限而永远不会在索引计算中使用的高位的影响。

首先需要知道的是二进制取余操作是怎么一回事:
举个例子,十进制11对4取余11%4 = 2 ....3,商为2,余数为3
11的二进制为1011,对4做除法就是右移2位,结果就是10(即是十进制的2),丢弃11(即十进制的3)
所以取余操作就是拿低位的数,只要和1进行与操作即可,又因为hashmap的容量是2的幂次方进行扩容的,所以长度-1是全部1111这样的二进制。所以公式就变成了value &(length-1);

用上面的例子就是length=4,length-1=3 转成二进制为11,11对4取余即1011&11 =11,答案很快就算出来了

二进制取余这里有个问题就是如果value太大,取余后,就会有很多数字都会有同一个余数,也就是会放到hashmap的同一个桶里,这样会加大冲突。
举个例子
1111110001 & 1111 = 0001,高位发生变化时1011110001 & 1111 = 00011001110001 & 1111 = 0001,也就是说在高位发生变化时,你最后算出来的索引都一样了,高位比特位没用上。
所以为了避免这种情况,HashMap将高16位与低16位进行异或,这样可以保证高位的数据也参与到与运算中来,以增大索引的散列程度。

引用下别人的图

image

参考:https://zhuanlan.zhihu.com/p/458305988

posted @ 2024-03-31 13:52  自律のalive  阅读(35)  评论(0编辑  收藏  举报