为什么equals中使用的所有字段也应该用在哈希码中?

时间:2017-11-09 22:25:01

标签: java equalsverifier

@Edit:我正在使用此库http://jqno.nl/equalsverifier/检查equalshashCode是否写得正确。

我们说我们有这个课程:

final class Why {
    private final int id;
    private final String name;

    Why(final int id, final String name) {
        this.id = id;
        this.name = name;
    }

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

        final Why why = (Why) o;

        if (id != why.id) return false;
        return name != null ? name.equals(why.name) : why.name == null;
    }

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

hashCode我只在id字段上转发,因为这会给我带来相当不错的非碰撞哈希值。值得注意的是,此hash方法符合equals-hashCode的所有规则。我不想做一些总结哈希的花哨技巧,即:

@Override
public int hashCode() {
    int result = id;
    result = 31 * result + (name != null ? name.hashCode() : 0);
    return result;
}

那么您能否使用EqualsVerifer方法中的equals方法的所有字段来解释默认为hashCode的原因?

java.lang.AssertionError: Significant fields: equals relies on subValue, but hashCode does not.

1 个答案:

答案 0 :(得分:2)

免责声明:我是EqualsVerifier的创建者。

它之所以成为默认行为,是因为它通常是一种很好的做法,EqualsVerifier希望鼓励其用户遵循良好做法。您希望hashCode分布尽可能大,以确保在使用基于散列的集合时具有良好的性能。

如果您有充分的理由做其他事情(从您的问题判断,看起来您可能有一个),您可以通过添加.suppress(Warning.STRICT_HASHCODE)来始终禁用此行为。

但我仍然想知道:如果您觉得需要在等号方法中加入name,显然您的id并不是唯一的。那么为什么不在hashCode中包含name?它不是 额外的工作,特别是因为您可以从IDE生成一个,或者只使用java.util.Objects.hash(id, name)