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

时间:2010-10-06 03:06:29

标签: java hashcode

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


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

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

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

6 个答案:

答案 0 :(得分:8)

Effective Java's recipe。这只是最好的来源,放下手。

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

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

  

使用非零初始值(...),因此哈希值会受到影响   哈希值(...)为零的初始字段。如果使用零则为   初始值(...)总体哈希值不受任何此类哈希值的影响   初始字段,可能会增加冲突。值17是任意的   ...
  选择乘法器37是因为它是奇数素数。如果它是和   乘法溢出,信息会因为乘法而丢失   两个相当于移位。使用素数的优点较少   很清楚,但为此目的使用素数是传统的。

答案 1 :(得分:6)

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

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

答案 2 :(得分:2)

使用Commons Lang的HashCodeBuilder

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

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

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

答案 3 :(得分:1)

使用IDE生成它。

答案 4 :(得分:0)

基本上,您的哈希码应该包含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方法,这是一个很好的做法。

答案 5 :(得分:0)

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