【发布时间】:2010-09-06 04:54:09
【问题描述】:
我一直认为应该重写 java 中的 .equals() 方法以使其特定于您创建的类。换句话说,要寻找两个不同实例的等价性,而不是对同一实例的两个引用。然而,我遇到过其他程序员,他们似乎认为应该不理会默认对象行为,并创建一个新方法来测试同一类的两个对象的等价性。
支持和反对重写 equals 方法的论据是什么?
【问题讨论】:
我一直认为应该重写 java 中的 .equals() 方法以使其特定于您创建的类。换句话说,要寻找两个不同实例的等价性,而不是对同一实例的两个引用。然而,我遇到过其他程序员,他们似乎认为应该不理会默认对象行为,并创建一个新方法来测试同一类的两个对象的等价性。
支持和反对重写 equals 方法的论据是什么?
【问题讨论】:
Equals 方法旨在比较引用。所以不应该重写它来改变它的行为。
如果需要,您应该创建一个新方法来测试不同实例中的等效性(或在某些 .NET 类中使用 CompareTo 方法)
【讨论】:
如果您想测试标准库类中的等价性(例如,确保 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 也有一个不错的overview of implementing equals and hashCode。
【讨论】:
对于可变对象,您应该“永远不要”覆盖 equals 和 getHashCode - 这适用于 .net 和 Java。如果你这样做了,并使用这样的对象作为 f.ex 字典中的键,然后 change 该对象,你就会遇到麻烦,因为字典依赖于哈希码来查找对象。
这里有一篇关于这个主题的好文章:http://weblogs.asp.net/bleroy/archive/2004/12/15/316601.aspx
【讨论】:
说实话,在 Java 中并没有真正反对覆盖 equals 的论据。如果您需要比较实例是否相等,那么您就是这样做的。
如上所述,您需要了解与 hashCode 的约定,同样,请注意 Comparable 接口周围的陷阱 - 在几乎所有情况下您都需要 由 Comparable 定义的自然排序 以与等于一致(有关规范的反示例,请参阅BigDecimal api 文档)
创建一个新的判断相等性的方法,除了不使用现有的库类之外,在某种程度上违背了 Java 约定。
【讨论】:
@David Schlosnagle mentions 提到了 Josh Bloch 的 Effective Java -- 这是任何 Java 开发人员的必读。
有一个相关的问题:对于不可变的值对象,您还应该考虑覆盖compare_to。如果它们不同,标准措辞在Comparable API:
一般是这样,但不严格要求 (compare(x, y)==0) == (x.equals(y))。一般来说,任何违反此条件的比较器都应清楚地表明这一事实。推荐的语言是“注意:这个比较器强加了与等号不一致的顺序。”
【讨论】: