我想知道为什么Hashtable避免使用负哈希码?
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
其中(hash & 0x7FFFFFFF)
使得有符号位为0为正,但为什么我们不能将带符号的32位整数视为无符号?甚至使用模块化技巧使其变得积极。例如,
public static long int_mod(int hashcode, int tab_length){
return (hashcode % tab_length + tab_length) % tab_length;
}
答案 0 :(得分:10)
该值必须介于0
和tab.length - 1
之间,因为它用作内部数组(在本例中为tab
)的索引,用于存储值(和溢出元素)。因此,它不能是消极的。
我认为(hash & 0x7FFFFFFF) % tab.length
优先使用(hashcode % tab.length + tab.length) % tab.length
,因为它会更快而不会过度增加碰撞的机会,但您必须找到设计文档或与原始开发人员交谈才能知道肯定的。
答案 1 :(得分:2)
......但为什么我们不能......
您在问为什么选择了特定的实现。没有人可以告诉你,除了代码的原始作者,如果他或她记得。
在代码中实现构思总是有多种方法。编写代码的人必须选择其中一个。事实上,为什么没有选择另一个特定的实现,这没有多大意义。
答案 2 :(得分:2)
如果你的容量保持2的幂,
private static final int CAPACITY = 64;
private static final int HASH_MASK = CAPACITY - 1;
final int index = obj.hashCode() & HASH_MASK;
基本上,除了您感兴趣的低位之外,屏蔽除了所有位置。假设较低的N位具有与整个哈希码一样的均匀分布。
答案 3 :(得分:1)
Java没有本机无符号类型。如果hashCode
具有负值,那么我们必须在我们使用hashCode
作为数组索引的任何地方应用此类屏蔽技巧。
答案 4 :(得分:1)
我们不能将signed int视为unsigned,这是一个很明显的理由:原始Java开发人员认为无符号支持是一种不必要的复杂问题,因为无符号算术可以是confusing。从那以后,这对Java来说还不是一个足够大的问题。
作为verdesmerald mentioned,因为没有明确的记录为什么(hash & 0x7FFFFFFF) % tab.length
被选择超出你的聪明修改的效果,虽然我们可以找到决定的理由,但最终我们只能推测为什么要这样做。
语义的最后一点,可能并不重要:Hashtable并没有使用负的哈希码,因为哈希码被“翻译”成索引的非负形式。
答案 5 :(得分:0)
除了他自己(也许是他的同事)之外,没有人可以告诉你为什么原始作者选择了该实现。无论如何它并不重要,因为它工作正常。
关于你的建议实施:它可能不会做你应该做的思考。您应该刷新java中的%运算符:For example here。将整数溢出添加到混合中,您建议的表达式可能会导致负值......