提问者:小点点

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


Eclipse源菜单有一个“generate hashCode/equals method”,它生成如下函数。

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;
}

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

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


共3个答案

匿名用户

您可以看到< code>java.util.ArrayList中hashCode函数的实现如下

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生成的代码遵循类似的实现方式。但是如果你觉得你必须自己实现你的hashCode,约书亚·布洛赫在他著名的《有效Java》一书中给出了一些很好的指导方针。我将从那本书的第9项中发布那些要点。那些是,

>

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

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

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

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

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

    四。如果字段是浮点数,则计算float . float pointbits(f)。

    五.如果字段是双精度的,计算Double.doubleToLongBits(f),然后哈希得到的long,如步骤2.a.iii.

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

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

    b、 将步骤2.a中计算的哈希代码c合并为以下结果:

       result = 31 * result + c;
    

    返回结果。

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

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

  • 匿名用户

    由于Java 7,您可以使用Java.util。对象编写简洁优雅的方法:

    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;
      }
    }
    

    匿名用户

    一般来说是好的,但是:

    1. 番石榴做得更好,我更喜欢。【编辑:似乎从JDK7开始,Java提供了类似的哈希函数】
    2. 有些框架在直接访问字段而不是使用setters/getter时可能会导致问题,例如Hibernate。对于Hibernate创建的一些惰性字段,它创建的是一个代理,而不是真正的对象。只有调用getter才能使Hibernate获得数据库中的实际值