如何覆盖这个hashCode方法?

时间:2012-06-11 20:30:36

标签: java

关于Person的定义:

public class Person {
    private int id;
    private int characteristics;
    public boolean equals (Object obj) {
           if (obj == this) {
                 return true;
           }
           if (obj instanceof Person) {
                 if (id == ((Person) obj).id) {
                     return true;
                 } else if (characteristics == ((Person) obj).characteristics) {
                     return true;
                 }
           }
           return false;
    }
}

如果Person返回a,则b个对象a.equals(b)true必须具有相同的哈希码,我应该如何实现hashCode方法?

溶液

根据Java的等价协议,我的equals方法实现不正确: transitivity 不满足:a.id = 1a.characteristic = 2b.id = 1,{ {1}},b.characteristic = 3c.id = 2; c.characteristic = 3a.equals(b) == true,但b.equals(c) == true

3 个答案:

答案 0 :(得分:5)

由于您的类在各自的idcharacteristics字段相等时认为对象相等,因此您可合理使用的唯一哈希码是所有实例的常量值:

public int hashCode() {
    return 0;
}

这将使基于散列的查找执行得非常糟糕。

equals()中的任何一项或测试通常都是一个坏主意;对象实际上不是相等,是吗?也许他们只是“相互匹配?”也许您应该考虑单独留下equals()并实施其他比较方法。


正如托马斯所指出的,你的equals()测试不是传递性的;如果a.equals(b) && b.equals(c)为真,那么a.equals(c)必须为真。对于您的重载,这为true,因此您的实现违反了equals() 的合同。我强烈建议您以不同的方法实施此测试,并单独留下equals()

答案 1 :(得分:1)

这是为您的班级自动生成的

@Override
public int hashCode() {
    int result = id;
    result = 31 * result + characteristics;
    return result;
}

经过几次重构:

@Override
public int hashCode() {
    return 31 * id + characteristics;
}

记录中,是仅仅是我还是你的equals()被打破了?如果id s或characteristics相等,则认为两个对象相等,但不一定两者都相同。这意味着您的平等不是 transitive ,一旦您的对象进入荒野,这可能会产生意想不到的副作用。

这是一个不错的实现:

@Override
public boolean equals(Object o) {
    if (this == o) {
        return true;
    }
    if (!(o instanceof Person)) {
        return false;
    }

    Person person = (Person) o;
    return characteristics == person.characteristics && id == person.id;
}

答案 2 :(得分:0)

如果具有相同的id意味着始终具有相同的characteristics(这似乎使equals()有效),那么您的哈希码可以单独使用characteristics

@Override
public int hashCode() {
    return characteristics;
}

如果情况并非如此,您可能需要重新考虑使用Java相等来表达这种关系,正如@cdhowie所暗示的那样。