【问题标题】:what is the preferred way of implementing hashCode()?实现 hashCode() 的首选方法是什么?
【发布时间】:2010-10-06 03:06:28
【问题描述】:

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


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

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

还有其他首选/标准的方式来实现 hashCode() 吗?

【问题讨论】:

标签: java hashcode


【解决方案1】:

Effective Java's recipe。它只是最好的来源,毫无疑问。

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

根据 Bloch 的说法(他使用 17 作为初始值,使用 37 作为常数乘数):

使用非零初始值 (...),因此哈希值将受到以下因素的影响 哈希值 (...) 为零的初始字段。如果零被用作 初始值 (...) 整体哈希值将不受任何此类影响 初始场,这可能会增加碰撞。值 17 是任意值。
...
选择乘数 37 是因为它是奇素数。如果它是均匀的 乘法溢出,信息会丢失,因为乘法 乘二相当于移位。使用素数的优点较少 很清楚,但传统上为此目的使用素数。

【讨论】:

  • CW,因为我只是在无耻地引用布洛赫。
  • 在 Effective Java 的第二版中,Josh Bloch 使用 31 而不是 37。他解释了这个选择:“31 的一个很好的特性是乘法可以用移位和减法代替,这样更好性能:31 * i == (i << 5) - i。现代虚拟机自动进行这种优化。”
【解决方案2】:

一个不错的选择是GuavaObjects.hashCode 方法。它接受任意数量的参数并基于它们创建一个哈希码:

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

【讨论】:

    【解决方案3】:

    使用来自 Commons Lang 的 HashCodeBuilder

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

    查看 API 以了解不使用反射的方法。您可以告诉它要包含哪些字段,或者忽略哪些字段。

    另请参阅 EqualsBuilder,了解如何覆盖 equals 方法。

    【讨论】:

      【解决方案4】:

      使用您的 IDE 生成它。

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          【解决方案6】:

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

          【讨论】:

            猜你喜欢
            • 2011-11-10
            • 1970-01-01
            • 1970-01-01
            • 2011-05-17
            • 1970-01-01
            • 2015-11-12
            • 1970-01-01
            • 2012-11-16
            • 2012-10-31
            相关资源
            最近更新 更多