我一直认为应该重写 java 中的 .equals() 方法以使其特定于您创建的类。换句话说,要寻找两个不同实例的等价性,而不是对同一实例的两个引用。然而,我遇到过其他程序员,他们似乎认为应该不理会默认对象行为,并创建一个新方法来测试同一类的两个对象的等价性。
支持和反对重写 equals 方法的论据是什么?
如果您想测试标准库类中的等价性(例如,确保 java.util.Set 包含唯一元素或使用对象作为 java.util.Map 对象中的键),则覆盖 equals 方法是必要的。
请注意,如果您覆盖 equals,请确保按照文档中的说明遵守 API 合同。例如,确保您还覆盖Object.hashCode:
如果两个对象根据 equals(Object) 方法相等,则对两个对象中的每一个调用 hashCode 方法必须产生相同的整数结果。
编辑:我没有将此作为关于该主题的完整答案发布,因此我将回应 Fredrik Kalseth 的声明,即覆盖 equals 最适合于immutable objects。引用Map的 API :
注意:如果将可变对象用作映射键,则必须非常小心。如果对象的值以影响等于比较的方式更改,而对象是映射中的键,则不指定映射的行为。
我强烈建议拿起一本 Effective Java 并阅读第 7 条,遵守equals contract。如果您为可变对象覆盖 equals,则需要小心,因为许多集合(例如 Maps 和 Sets)使用 equals 来确定等价,并且更改集合中包含的对象可能会导致意外结果。Brian Goetz 对实现 equals 和 hashCode 也有很好的概述。
对于可变对象,您应该“从不”覆盖 equals 和 getHashCode - 这适用于 .net 和 Java。如果你这样做了,并使用这样的对象作为 f.ex 字典中的键,然后更改该对象,那么你将遇到麻烦,因为字典依赖于哈希码来查找对象。
这是一篇关于这个主题的好文章:http ://weblogs.asp.net/bleroy/archive/2004/12/15/316601.aspx
@David Schlosnagle提到了Josh Bloch 的Effective Java——这是任何 Java 开发人员的必读之书。
有一个相关的问题:对于不可变的值对象,您还应该考虑覆盖compare_to
. 如果它们不同,标准措辞在Comparable API中:
通常是这样,但并不严格要求 (compare(x, y)==0) == (x.equals(y))。一般来说,任何违反此条件的比较器都应清楚地表明这一事实。推荐的语言是“注意:这个比较器强加了与等于不一致的排序。”
Equals 方法旨在比较引用。所以不应该重写它来改变它的行为。
如果需要,您应该创建一个新方法来测试不同实例中的等效性(或在某些 .NET 类中使用 CompareTo 方法)
老实说,在 Java 中并没有真正反对覆盖equals的论点。如果您需要比较实例是否相等,那么您就是这样做的。
如上所述,您需要了解与hashCode的约定,同样,请注意Comparable接口周围的陷阱- 在几乎所有情况下,您都希望Comparable 定义的自然顺序与 equals 一致(请参阅BigDecimal用于规范反例的 api doc)
除了不使用现有的库类之外,创建一个确定相等性的新方法在某种程度上违背了 Java 约定。