Java HashMap 里,在 getNode 方法中关于&的一个问题。

2019-06-04 13:25:03 +08:00
 ukipoi

HashMap.java里第 569 行,tab[(n - 1) & hash]&的意思是随机取一个小于等于 n-1 的值吗?

2418 次点击
所在节点    Java
8 条回复
tchqiq
2019-06-04 13:39:40 +08:00
可以这么认为.hash 是用高 16 位和低 16 位异或得到.所以更为"随机"
cookii
2019-06-04 13:42:50 +08:00
n 是之前获取的 table 的长度,n 的值总是 2 的次方(16/32/64/128...),(n-1)转换成二进制低位全部是 1,和 hash 值&操作相当于对 n 取余。
ukipoi
2019-06-04 14:03:57 +08:00
@imzhoukunqiang 请教一下为什么 n 的值总是 2 的次方呢?关于我的 第 1 条附言 希望能解答一下
neuthself
2019-06-04 14:07:55 +08:00
jdk1.7 中 HashMap 通过 h & (length-1) 来得到数组位置,而底层数组的长度总是为 2 的 n 次方。当 length 为 2 的 n 次方时,h & (length-1) 运算等价与对 length 取模,也就是 h % length,但是 & 比 % 具有更高的效率。

jdk1.8 中 HashMap 优化了高位运算的算法,通过 hashcode() 的高 16 位异或低 16 位实现的: (h = key.hashCode()) ^ (h >>> 16) ,这样做可以在数组 table 的 length 比较小的时候,也能保证考虑到高低 Bit 都参与到 hash 运算中,同时不会有太大的开销。
neuthself
2019-06-04 14:08:42 +08:00
并且由于每次扩容是上一次的两倍。Jdk1.8 中,扩容之后元素要么是在原来的位置,要么实在原来的位置再移动 2 次幂的位置。
cookii
2019-06-04 14:22:19 +08:00
@ukipoi table 的 length ≠ map 的 size,此时 table 的 size 应该是 16 吧(默认容量 没记错的话),,hashmap 中 table 长度是由 tableSizeFor(int cap)计算得来的。这个方法总会返回最接近且大于等于 cap 的 2 的幂。 使用这个方法取余的原因可以参照 4L 说的,效率问题。
Caturra
2019-06-04 14:22:48 +08:00
@ukipoi 不严谨的说下自己的想法,n 保持 2 的幂可以保证 n-1 永远是二进制全 1,符合原来算法的实现(&hash 那一段,替代性能低下的 mod 操作),其次,假设( n-1 )&hash 在扩容前算法足够均匀( hash 的处理是和自己的高 16 位取 xor ),那下一个 index 比原来的 index 在二进制上只是多了最高位的 0 和 1 的区别,也就是只要重新分布一半数目的 index 即可
limuyan44
2019-06-04 16:37:39 +08:00
就是为了扩容不二次 hash 而已

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/570718

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX