我应该用对hashCode()的调用重写equals()吗



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

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

之后,我想如果我错误地覆盖了hashCodeequals也不会工作。然而,上面的实现对我来说似乎是"正确的",因为我认为哈希码是使对象相等的东西。

附言:别告诉我这是个人喜好。我认为这一定有一个标准,对吧?而且我也非常愿意遵守标准。

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

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