何时需要重写equals和hashCode方法?

13

可能是重复问题:
在Java中覆盖equals和hashCode方法

如果我有

class A {
    int x = 1;
}
...
A a1 = new A();
A a2 = new A();
a1.equals(a2);

如果我比较两个A的实例,而没有覆盖equals方法,我会得到预期的结果吗?


这与https://dev59.com/M3VD5IYBdhLWcg3wTJrF有关,但并非重复,因为那是关于如何覆盖`equals`和`hashCode`,而这是关于何时覆盖的问题。 - Raedwald
这似乎是一个更好的重复问题链接:https://dev59.com/eGYr5IYBdhLWcg3wytLe - Tom Zych
3个回答

33
如果我比较两个A的实例而没有覆盖equals方法,那么我会得到预期结果吗?
这取决于你的期望值:)
默认实现将给你"引用相等性" - 也就是说,当你比较两个引用时,equals只有在它们是同一个对象的引用时才返回true。
通常情况下,你会重写equals来实现"value equality" - 意味着两个不同的对象被认为是相等的,通常由于它们本身具有相等的字段值。相等的确切含义将取决于你的设计 - 两个对象仍然可以以其他方式可区分,例如。
如果你重写了equals,你应该同时重写hashCode以与equals一致,使得如果a.equals(b)为true,则a.hashCode() == b.hashCode()。这将允许你的类的实例被用作哈希集合(例如HashMap)中的键,以便你可以基于与原始键对象"相等"的键查找值,而不必使用对精确原始键对象的引用。

8
那是不是意味着,如果我不覆盖equals方法,那么equals()和==作用相同? - user926958
8
是的,完全正确。 - Jon Skeet

4
如果我比较两个A的实例而没有覆盖equals方法,我会得到预期的结果吗?
不会。因为你明确创建了两个不同的实例。
为什么?equals的默认实现检查两个相关对象是否指向Java虚拟内存中的相同内存位置(这个默认行为在java.lang.Object.equals()中定义)。
何时需要重写equals和hashcode方法?
程序员最常重写equals()和hashcode()的情况是:
1.作为java.util.Map实现中的键。 2.作为java.util.Set实现中的值。 3.您想要检查同一类的两个不同实例之间的值的相等性(在这种情况下,覆盖equals()是强制性的,但是hashcode()不是——但是这是一个好的编程习惯)。
equals和hashcode的一般协定是:
if a1.equals(a2)
    it is mandatory that a1.hashcode() == a2.hashcode()
if a1.hashcode() == a2.hashcode()
    it is not mandatory that a1.equals(a2)

我猜这已经是一天足够处理的数据了 :)


2

equals的默认实现是测试变量是否引用同一对象。如果这不是您想要的,那么您需要覆盖equals。当您覆盖equals时,通常需要覆盖hashcode以便该对象可用于哈希表(或其他使用哈希码的数据结构)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接