为啥 Java 使用 (hash & 0x7FFFFFFF) % tab.length 来决定键的索引?
Posted
技术标签:
【中文标题】为啥 Java 使用 (hash & 0x7FFFFFFF) % tab.length 来决定键的索引?【英文标题】:Why does Java use (hash & 0x7FFFFFFF) % tab.length to decide the index of a key?为什么 Java 使用 (hash & 0x7FFFFFFF) % tab.length 来决定键的索引? 【发布时间】:2012-03-11 22:43:45 【问题描述】:从下面的链接中,我知道 Java 使用 (hash & 0x7FFFFFFF) % tab.length
来决定将 key, value 放入数组的哪个槽。
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7-b147/java/util/Hashtable.java#Hashtable.put%28java.lang.Object%2Cjava.lang.Object%29
我的问题是为什么 Java 首先做 hash & 0x7FFFFFFF?有什么特别的目的吗?
【问题讨论】:
我认为这是为了确保键始终是正整数,这样您就不会尝试使用负数组索引。 假设它不会。例如,-12345678 % 37 是多少? 是 ConcurrentHashMap 的 "hash & (tab.length - 1)" 和 hashtable 的 "(hash & 0x7FFFFFFF) % tab.length" 一样吗? 【参考方案1】:因为-1 % 10 == -1
您肯定不希望将其索引到数组中。强制符号位为 0 可以避免这个问题。
【讨论】:
是的,该死的,我忘记了可能的负哈希码。谢谢 @plzdontkillme 因为 math.abs 并不总是返回正数。此外,取决于编译器和架构,它的效率会更高或更高。 谢谢 Voo,非常感谢 @plzdontkillme 详细说明,Math.abs(-2^-31) 是 -2^-31,因为没有 2^31。【参考方案2】:请注意,Hashtable
或多或少已经过时,已被HashMap
取代。这个使用hash & (table.length-1)
来达到同样的目的。
它之前也做了一些位移,可以看到here。这是为了应对 hashCode()
方法的错误实现,该方法返回的数字多样性较低。
【讨论】:
【参考方案3】:因为:
0x7FFFFFFF
是 0111 1111 1111 1111 1111 1111 1111 1111 :除符号位外全为 1。
(hash & 0x7FFFFFFF)
将产生一个正整数。
(hash & 0x7FFFFFFF) % tab.length
将在制表符长度范围内。
【讨论】:
+1 很好的解释。然而我有一个疑问。 ConcurrentHashMap 的“hash & (tab.length - 1)”是否与 hashtable 的“(hash & 0x7FFFFFFF) % tab.length”相同? 很好的解释! 完美的解释。我什至不需要这个代码,但对于类似的我正在看的东西是有意义的。谢谢!以上是关于为啥 Java 使用 (hash & 0x7FFFFFFF) % tab.length 来决定键的索引?的主要内容,如果未能解决你的问题,请参考以下文章