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

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

int hashCode(){ return 31 * 31 * a.hashCode() + 31 * b.hashCode() + c.hashCode(); } 

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

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

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

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

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

使用非零初始值(…),因此哈希值将受哈希值(…)为零的初始字段的影响。 如果将零用作初始值(…),则整个散列值将不受任何此类初始字段的影响,这可能会增加冲突。 值17是任意的。

选择乘法器37是因为它是奇数素数。 如果它是偶数并且乘法溢出,则信息将丢失,因为乘以2相当于移位。 使用素数的优点不太清楚,但为此目的使用素数是传统的。

一个不错的选择是Guava的Objects.hashCode方法。 它需要任意数量的参数,并根据它们创建一个哈希码:

 @Override public int hashCode() { return Objects.hashCode(a, b, c); } 

使用Commons Lang的HashCodeBuilder :

 public int hashCode() { return HashCodeBuilder.reflectionHashCode(this); } 

有关不使用reflection的方法,请参阅API。 您可以告诉它要包含哪些字段,或忽略哪些字段。

另请参见EqualsBuilder,用于覆盖equals方法。

使用IDE生成它。

基本上,您的哈希码应该包含POJO的关键参数。 一个例子如下。

 public int hashCode() { int hash = 0; if (getRollId() != null) { hash += getRollId().hashCode(); } if (getName() != null) { hash += getName().hashCode(); } return hash == 0 ? System.identityHashCode(this) : hash; } 

在上面的示例中,roll id和name是该POJO的关键参数。

如果只将这些参数添加到您在同一POJO的Eqauls方法中添加的hashCode方法,这是一个很好的做法。

我相信以下是一个简单场景的好习惯:如果你的类包含任何只读成员,它们将是生成对象的哈希码的良好候选者。 但是,如果您的类只包含变异成员,则可以创建一个readonly int字段,该字段根据传递给构造函数的非null值获取值。