Eclipse 3.5有一个非常好的功能,可以生成Java hashCode()函数。例如,它会生成以下内容(稍微缩短):
class HashTest {
int i;
int j;
public int hashCode() {
final int prime = 31;
int result = prime + i;
result = prime * result + j;
return result;
}
}
如果类中有更多的属性,则对于每个额外的属性,result = prime * result + attribute.hashCode();
将重复执行。对于int类型,可以省略使用.hashCode()。
这似乎没问题,但是选择31作为质数可能源自Java String的hashCode实现,该实现由于硬件乘法器的引入而已经过时。在此情况下,对于i和j的小值,会出现许多哈希碰撞:例如(0,0)和(-1,31)具有相同的值。我认为这是一件坏事(TM),因为小值经常出现。对于String.hashCode,您还会发现许多哈希码相同的短字符串,例如"Ca"和"DB"。如果选择一个大质数,则此问题将消失,如果正确选择质数,则问题将消失。
所以我的问题是:选择哪个好的质数?您如何应用标准来找到它?
这是一个通用问题 - 所以我不想给出i和j的范围。但我认为在大多数应用程序中,相对较小的值比大值更常见。(如果有大值,则质数的选择可能无关紧要。)这可能没有太大的区别,但更好的选择是改善此问题的简单明显方法 - 那么为什么不这样做呢?Commons lang的HashCodeBuilder也建议使用奇怪的小值。
(澄清:这不是为什么Java中的String使用31作为乘数的hashCode()是重复的?,因为我的问题与JDK中31的历史无关,而是关于在使用相同基本模板的新代码中应该选择更好的值。那里的答案都没有试图回答这个问题。)
*31
可以在一条指令中完成。实际上,任何奇数,无论是否为质数,都足够好。 - Tom Hawtin - tacklinep = (2^n-1)
的质数有助于优化x * p = (p << n) - p
,这通常由编译器完成。引自 Joshua Bloch 的《Effective Java》第3章第9条。关于此问题的 Stack Overflow 帖子:https://dev59.com/gnVC5IYBdhLWcg3wbQfA#299748 - corsiKa2^n-1
、质数、较小的值会给出31。 - J-16 SDiZ