Java8 为什么这里把key的hashcode取出来,然后把它右移16位,然后取异或?
文章目录【深入源码】图解 HashMap 扰动函数为什么要把高位“揉”进低位1. 核心矛盾被浪费的“40亿”2. 案例实战如果不“扰动”会发生什么未经扰动的下标计算3. 扰动函数介入h ^ (h 16)演示 A 的变换过程演示 B 的变换过程4. 最终对比碰撞消失了思维误区:其实原来哈希冲突的原因就是因为低位雷同,现在h(h16)就是保证高16和低16位都是原值的高位信息,导致你h(n-1)就是用不一样的高位去取模计算索引位置了?1. 修正一个小偏差是“混合”而非“覆盖”2. 为什么能减少冲突逻辑闭环3. 一个直观的对比【深入源码】图解 HashMap 扰动函数为什么要把高位“揉”进低位在阅读 HashMap 源码时很多小伙伴会被(h key.hashCode()) ^ (h 16)这一行代码困惑。为什么要右移 16 位为什么要进行异或本文通过一个具体的案例带你像剥洋葱一样看透这个“扰动函数”的奥秘。1. 核心矛盾被浪费的“40亿”hashCode是一个 32 位的整数范围高达 40 亿。但现实中我们的初始数组长度往往只有 16。在计算下标时公式为(n - 1) hash。如果数组长度为 16计算过程只取决于最后 4 位。这意味着即便高位有再大的差异只要低 4 位相同就一定会发生哈希碰撞。2. 案例实战如果不“扰动”会发生什么假设我们有两个哈希值h A h_AhA和h B h_BhB它们的高位差异极大但低位完全一模一样h A h_AhA:1111 0000 0000 0000 | 0000 0000 0000 0101h B h_BhB:0101 0101 0101 0101 | 0000 0000 0000 0101未经扰动的下标计算当n 16时(16 - 1)的二进制是1111。A 的下标:...0101 1111 5B 的下标:...0101 1111 5结果:发生严重碰撞高位的差异被完全忽略了3. 扰动函数介入h ^ (h 16)扰动函数的目的就是让高 16 位的特征“掉下来”混合到低 16 位中。演示 A 的变换过程原值h A h_AhA:1111 0000 0000 0000 | 0000 0000 0000 0101右移 16 位:0000 0000 0000 0000 | 1111 0000 0000 0000异或运算:1111 0000 0000 0000 | 0000 0000 0000 0101 (原值) ^ 0000 0000 0000 0000 | 1111 0000 0000 0000 (移位值) ------------------------------------------- 1111 0000 0000 0000 | 1111 0000 0000 0101 (扰动结果)最终 A 的低 4 位仍为0101十进制 5。演示 B 的变换过程原值h B h_BhB:0101 0101 0101 0101 | 0000 0000 0000 0101右移 16 位:0000 0000 0000 0000 | 0101 0101 0101 0101异或运算:0101 0101 0101 0101 | 0000 0000 0000 0101 (原值) ^ 0000 0000 0000 0000 | 0101 0101 0101 0101 (移位值) ------------------------------------------- 0101 0101 0101 0101 | 0101 0101 0101 0000 (扰动结果)最终 B 的低 4 位变为了0000十进制 0。4. 最终对比碰撞消失了处理方式A 的下标B 的下标结果直接取低位55碰撞扰动后再取50分流成功深度总结原本 A 和 B 的低 4 位完全相同。但通过右移 16 位A 的高位特征1111和 B 的高位特征0101分别“揉”进了自己的低位。即使你的数组很小这种机制也强制让 32 位信息中的每一位都参与了最终的下标运算。这就是利用“40亿”种可能性来减少碰撞的精髓所在。思维误区:其实原来哈希冲突的原因就是因为低位雷同,现在h(h16)就是保证高16和低16位都是原值的高位信息,导致你h(n-1)就是用不一样的高位去取模计算索引位置了?你已经抓住了核心逻辑但有一个小细节需要修正不是“都是高位信息”而是“融合了高低位的信息”。你的理解中有一个很棒的洞察“用不一样的高位去计算索引位置”。没错就是通过“借位”的思想让本来不参与运算的高位变相地参与了运算。为了确保你面试时描述得绝对精准我们把这个逻辑最后梳理一下1. 修正一个小偏差是“混合”而非“覆盖”你提到的h ^ (h 16)高 16 位因为右移后高位补 0h ^ 0还是原值。所以高 16 位保持不变。低 16 位变成了原低16位 ^ 原高16位。所以并不是说低位变成了纯高位信息而是低位现在承载了全 32 位的“综合特征”。2. 为什么能减少冲突逻辑闭环原本的死穴n-1比如 15像是一个只看身份证最后 4 位的保安。只要最后 4 位一样他就觉得是同一个人。现在的解决办法在过保安岗之前我们先做一个动作——把身份证的前 16 位和后 16 位做一次异或。结果即使两个人的身份证后 4 位原本一样但只要前 16 位有任何不同异或后的“新后 4 位”大概率就不一样了。3. 一个直观的对比假设数组长度为 16即 1111没有扰动时Key1:0000...000111111Key2:1111...000111111冲突虽然 Key2 高位全是 1但被保安无视了有了扰动后Key1: 低位还是接近0001。Key2: 低位变成了0001 ^ 11111110。Key2计算索引1110111114。冲突解除高位的1111成功自救把 Key2 送到了 14 号位置。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2544797.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!