20

我一直认为应该重写 java 中的 .equals() 方法以使其特定于您创建的类。换句话说,要寻找两个不同实例的等价性,而不是对同一实例的两个引用。然而,我遇到过其他程序员,他们似乎认为应该不理会默认对象行为,并创建一个新方法来测试同一类的两个对象的等价性。

支持和反对重写 equals 方法的论据是什么?

4

7 回答 7

19

如果您想测试标准库类中的等价性(例如,确保 java.util.Set 包含唯一元素或使用对象作为 java.util.Map 对象中的键),则覆盖 equals 方法是必要的。

请注意,如果您覆盖 equals,请确保按照文档中的说明遵守 API 合同。例如,确保您还覆盖Object.hashCode

如果两个对象根据 equals(Object) 方法相等,则对两个对象中的每一个调用 hashCode 方法必须产生相同的整数结果。

编辑:我没有将此作为关于该主题的完整答案发布,因此我将回应 Fredrik Kalseth 的声明,即覆盖 equals 最适合于immutable objects。引用Map的 API :

注意:如果将可变对象用作映射键,则必须非常小心。如果对象的值以影响等于比较的方式更改,而对象是映射中的键,则不指定映射的行为。

于 2008-08-19T17:14:47.760 回答
8

我强烈建议拿起一本 Effective Java 并阅读第 7 条,遵守equals contract。如果您为可变对象覆盖 equals,则需要小心,因为许多集合(例如 Maps 和 Sets)使用 equals 来确定等价,并且更改集合中包含的对象可能会导致意外结果。Brian Goetz 对实现 equals 和 hashCode 也有很好的概述

于 2008-08-19T17:21:29.057 回答
4

对于可变对象,您应该“从不”覆盖 equals 和 getHashCode - 这适用于 .net 和 Java。如果你这样做了,并使用这样的对象作为 f.ex 字典中的键,然后更改该对象,那么你将遇到麻烦,因为字典依赖于哈希码来查找对象。

这是一篇关于这个主题的好文章:http ://weblogs.asp.net/bleroy/archive/2004/12/15/316601.aspx

于 2008-08-19T17:28:02.507 回答
2

@David Schlosnagle提到了Josh Bloch 的Effective Java——这是任何 Java 开发人员的必读之书。

有一个相关的问题:对于不可变的值对象,您还应该考虑覆盖compare_to. 如果它们不同,标准措辞在Comparable API中:

通常是这样,但并不严格要求 (compare(x, y)==0) == (x.equals(y))。一般来说,任何违反此条件的比较器都应清楚地表明这一事实。推荐的语言是“注意:这个比较器强加了与等于不一致的排序。”

于 2008-08-19T20:46:45.007 回答
0

Equals 方法旨在比较引用。所以不应该重写它来改变它的行为。

如果需要,您应该创建一个新方法来测试不同实例中的等效性(或在某些 .NET 类中使用 CompareTo 方法)

于 2008-08-19T17:08:39.660 回答
0

equals()如果在将对象添加到已排序的数据结构(SortedSet等)时需要特定行为,则只需要覆盖该方法

当你这样做时,你还应该覆盖hashCode().

有关完整说明,请参见此处

于 2008-08-19T17:15:41.157 回答
0

老实说,在 Java 中并没有真正反对覆盖equals的论点。如果您需要比较实例是否相等,那么您就是这样做的。

如上所述,您需要了解与hashCode的约定,同样,请注意Comparable接口周围的陷阱- 在几乎所有情况下,您都希望Comparable 定义的自然顺序与 equals 一致(请参阅BigDecimal用于规范反例的 api doc)

除了不使用现有的库类之外,创建一个确定相等性的新方法在某种程度上违背了 Java 约定。

于 2008-08-19T19:50:42.967 回答