Eclipse生成的hashCode函数是否有用?

ams*_*ams 31 java eclipse hash hashtable hashmap

Eclipse源菜单有一个"生成hashCode/equals方法",它生成如下所示的函数.

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;
}
Run Code Online (Sandbox Code Playgroud)

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

我不是哈希函数的专家,我想知道生成的哈希函数是多么"好"?在什么情况下它会崩溃并导致太多碰撞?

sak*_*dar 17

你可以在java.util.ArrayListas中看到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;
}
Run Code Online (Sandbox Code Playgroud)

这是一个这样的例子,您生成的Eclipse代码遵循类似的实现方式.但是如果你觉得你必须自己实现你的hashCode,那么Joshua Bloch在他着名的书" Effective Java"中给出了一些很好的指导.我将从那本书的第9项中发布那些重要的观点.那些是,

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

    一个.计算字段的int哈希码c:

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

    II.如果字段是byte,char,short或int,则为compute(int)f.

    III.如果字段是long,则计算(int)(f ^(f >>> 32)).

    IV.如果该字段是浮点数,请计算Float.floatToIntBits(f).

    v.如果该字段是double,则计算Double.doubleToLongBits(f),然后在步骤2.a.iii中散列生成的long.

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

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

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

       result = 31 * result + c;
    
    Run Code Online (Sandbox Code Playgroud)
  3. 返回结果.

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

Java语言设计者和Eclipse似乎遵循我想的类似指南.快乐的编码.干杯.


lef*_*bit 13

从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;
  }
}
Run Code Online (Sandbox Code Playgroud)


Eug*_*ene 5

一般来说它很好,但是:

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