实现hashCode()的首选方法是什么?

dol*_*eng 8 java hashcode

有时我需要通过组合其几个实例成员的hashCodes来实现obj的hashCode()方法.例如,如果组合obj有成员a,b和c,我经常看到ppl将其实现为


int hashCode(){
   return 31 * 31 * a.hashCode() + 31 * b.hashCode() + c.hashCode();
}
Run Code Online (Sandbox Code Playgroud)

这个神奇的数字31来自哪里?它是4字节的长度还是只是素数?

有没有其他优选/标准的方法来实现hashCode()?

Mar*_*ers 8

请参阅Effective Java的配方.这只是最好的消息来源.

使用素数只是为了在不知道域的情况下尝试获得相当好的分布.溢出到相同的值需要一段时间.如果我没记错的话,值31非常随意.

根据布洛赫(他使用17作为初始值,37作为常数乘数):

使用非零初始值(...),因此哈希值将受哈希值(...)为零的初始字段的影响.如果将零用作初始值(...),则整个散列值将不受任何此类初始字段的影响,这可能会增加冲突.值17是任意的.
...
选择乘法器37是因为它是一个奇数素数.如果它是偶数并且乘法溢出,则信息将丢失,因为乘以2相当于移位.使用素数的优点不太清楚,但为此目的使用素数是传统的.

  • 在Effective Java的第二版中,Josh Bloch使用31而不是37.他解释了这个选择:"31的一个很好的属性是乘法可以用移位和减法代替以获得更好的性能:`31*i == (i << 5) - i`.现代VM自动进行这种优化." (4认同)

Col*_*inD 6

一个很好的选择是番石榴Objects.hashCode方法.它需要任意数量的参数并根据它们创建一个哈希码:

@Override public int hashCode() {
  return Objects.hashCode(a, b, c);
}
Run Code Online (Sandbox Code Playgroud)