Eclipse生成的hashCode函数有什么好处吗?

2022-09-01 09:52:40

Eclipse源菜单有一个“生成哈希码/等于方法”,它生成如下函数。

String name; 
@Override
public int hashCode()
{
    final int prime = 31;
    int result = 1;
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    return result;
}

@Override
public boolean equals(Object obj)
{
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    CompanyRole other = (CompanyRole) obj;
    if (name == null)
    {
        if (other.name != null)
            return false;
    } else if (!name.equals(other.name))
        return false;
    return true;
}

如果我在生成时选择多个字段,Eclipse 将使用相同的模式,如上所示。hashCode()equals()

我不是哈希函数方面的专家,我想知道生成的哈希函数有多“好”?在什么情况下它会发生故障并导致太多的碰撞?


答案 1

您可以看到哈希码函数的实现java.util.ArrayList

public int hashCode() {
    int hashCode = 1;
    Iterator<E> i = iterator();
    while (i.hasNext()) {
        E obj = i.next();
        hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());
    }
    return hashCode;
}

就是这样一个例子,Eclipse 生成的代码遵循类似的实现方式。但是,如果你觉得你必须自己实现你的哈希码,那么Joshua Bloch在他的着名著作《Effective Java》中给出了一些很好的指导方针。我将发布该书第9项中的那些要点。这些是,

  1. 将一些常量非零值(例如 17)存储在称为 result 的 int 变量中。
  2. 对于对象中的每个有效字段 f(即 equals 方法考虑的每个字段),请执行以下操作:

    一个。计算字段的整型哈希代码 c:

    i. 如果字段是布尔值,则计算 (f ? 1 : 0)。

    ii. 如果字段是字节、字符、短整型或整型,则计算 (int) f。

    iii. 如果字段很长,则计算 (int) (f ^ (f >>> 32))。

    iv. 如果该字段是浮点数,则计算 Float.floatToIntBits(f)。

    v. 如果字段是双精度值,则计算 Double.doubleToLongBits(f),然后对生成的 long 进行哈希处理,如步骤 2.a.iii 中所示。

    vi. 如果字段是对象引用,并且此类的 equals 方法通过递归调用 equals 来比较字段,则以递归方式在该字段上调用 hashCode。如果需要更复杂的比较,请为此字段计算“规范表示”,并在规范表示上调用 hashCode。如果字段的值为 null,则返回 0(或其他一些常量,但 0 是传统的)

    vii. 如果字段是数组,请将其视为每个元素都是单独的字段。也就是说,通过递归应用这些规则来计算每个重要元素的哈希代码,并按步骤 2.b 组合这些值。如果数组字段中的每个元素都很重要,则可以使用 1.5 版中添加的 Arrays.hashCode 方法之一。

    b.将步骤 2.a 中计算的哈希代码 c 合并到结果中,如下所示:

       result = 31 * result + c;
    
  3. 返回结果。

  4. 编写完 hashCode 方法后,问问自己相等的实例是否具有相等的哈希代码。编写单元测试来验证您的直觉!如果相等的实例具有不相等的哈希代码,请找出原因并解决问题。

我想Java语言设计师和Eclipse似乎遵循类似的指导方针。快乐编码。干杯。


答案 2

从Java 7开始,你可以用它来编写简短而优雅的方法:java.util.Objects

class Foo {
  private String name;
  private String id;

  @Override
  public int hashCode() {
    return Objects.hash(name,id);
  }

  @Override
  public boolean equals(Object obj) {
    if (obj instanceof Foo) {
      Foo right = (Foo) obj;
      return Objects.equals(name,right.name) && Objects.equals(id,right.id);
    }
    return false;
  }
}

推荐