在Java中覆盖equals和hashCode时应该考虑哪些问题?


在Java中覆盖equals和hashCode时应该考虑哪些问题?


理论:

equals()(javadoc)必须定义等价关系(它必须是自反,对称和传递)。此外,它必须是一致的(如果未修改对象,则必须保持返回相同的值)。此外,o.equals(null)必须始终返回false。

hashCode()(javadoc)也必须是一致的(如果对象没有被修改equals(),它必须保持返回相同的值)。

这两种方法之间的关系是:

无论何时a.equals(b),a.hashCode()必须与之相同b.hashCode()。

在实践中:

如果你覆盖一个,那么你应该覆盖另一个。

使用您用于计算的同一组字段equals()进行计算hashCode()。

使用优秀的辅助类EqualsBuilder和HashCodeBuilder从阿帕奇共享库。一个例子:

public class Person {
    private String name;
    private int age;
    // ...

    @Override
    public int hashCode() {
        return new HashCodeBuilder(17, 31). // two randomly chosen prime numbers
            // if deriving: appendSuper(super.hashCode()).
            append(name).
            append(age).
            toHashCode();
    }

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

        Person rhs = (Person) obj;
        return new EqualsBuilder().
            // if deriving: appendSuper(super.equals(obj)).
            append(name, rhs.name).
            append(age, rhs.age).
            isEquals();
    }
}

还要记住:

使用基于散列的集合或映射(如HashSet,LinkedHashSet,HashMap,Hashtable或WeakHashMap)时,请确保在对象位于集合中时,放入集合的键对象的hashCode()永远不会更改。确保这一点的防弹方法是使您的密钥不可变,这也有其他好处。