我应该通过调用 hashCode() 来覆盖 equals() 吗?

Should I override equals() with calls to hashCode()?

我正在编写一个具有 "Achievements" 系统的应用程序,类似于 Stack Overflow 的徽章。我也在使用 SugarORM 来存储成就的进度。这是 Achievement class:

public class Achievement extends SugarRecord<Achievement>{
    @StringRes
    public int shortNameId;
    @StringRes
    public int descriptionId;
    public int progressNow;
    public int fullProgress; 
    //I am afraid that Sugar ORM will ignore private fields 
    //so I made them public. Please tell me if Sugar ORM does
    //not ignore those.
}

现在我想覆盖 equals。这很容易。

@Override
public boolean equals (Object other) {
    if (other == null) return false;
    if (!(other instanceof Achievement)) return false;
    Achievement a = (Achievement)other;
    return a.shortNameId == shortNameId &&
            a.descriptionId == descriptionId &&
            a.fullProgress == fullProgress;
}

然后我想起如果我覆盖equals,我应该总是覆盖hashCode。根据 Joshua Bloch 的 Effective Java,我这样写 hashCode 方法:

@Override
public int hashCode () {
    int result = 17;
    result = result * 31 + shortNameId;
    result = result * 31 + descriptionId;
    result = result * 31 + fullProgress;
    return result;
}

然后我认为我应该将 equals 的实现更改为

@Override
public boolean equals (Object other) {
    if (other == null) return false;
    if (!(other instanceof Achievement)) return false;
    Achievement a = (Achievement)other;
    return a.hashCode() == hashCode ();
}

后来我想如果我把hashCode覆盖错了,equals也不行。但是,上面的实现对我来说似乎 "right",因为我认为哈希码是使对象相等的原因。

P.S。不要告诉我这是个人喜好。我认为这必须有一个标准,对吗?而且我也很愿意遵守标准。

一般来说 a.hashCode()==b.hashCode() 并不意味着 a.equals(b) 一定是真的。因此,您不应依赖 hashCode 来确定相等性。

然而,另一个方向是正确的。如果 a.equals(b) 那么 a.hashCode() 必须等于 b.hashCode().