覆盖equals方法与创建新方法
我一直认为应该重写Java中的.equals()方法,使其特定于我们创建的类。换句话说,要寻找两个不同实例的等效性,而不是对同一实例的两个引用。但是,我遇到了其他程序员,他们似乎认为默认对象的行为应该保留下来,并创建一个新的方法来测试同一类的两个对象的等效性。
支持和反对覆盖equals方法的论点是什么?
解决方案
回答
Equals方法用于比较参考。因此,不应更改它来更改其行为。
如果需要,我们应该创建一个新方法来测试不同实例中的等效性(或者在某些.NET类中使用CompareTo方法)
回答
如果要在标准库类中测试等效性,则必须重写equals方法(例如,确保java.util.Set包含唯一元素或者将对象用作java.util.Map对象中的键)。
请注意,如果我们覆盖等号,请确保遵守文档中所述的API合同。例如,确保我们还重写Object.hashCode:
If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
编辑:我没有将其作为主题的完整答案发布,所以我会回应弗雷德里克·卡尔塞斯(Fredrik Kalseth)的说法,即重写等于最适合不可变对象。引用Map API:
Note: great care must be exercised if mutable objects are used as map keys. The behavior of a map is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is a key in the map.
回答
如果在将对象添加到排序的数据结构(例如,SortedSet等)中时想要特定的行为,则只需要重写equals()方法即可。
当你这样做的时候,你也应该重写hashCode()
。
请参阅此处以获取完整说明。
回答
我强烈建议我们选择《有效Java》的副本,并遵守平等合同,通读第7项。如果要覆盖可变对象的相等值,则需要小心,因为诸如Maps和Sets之类的许多集合都使用相等值来确定等效性,并且对集合中包含的对象进行变异可能会导致意外结果。 Brian Goetz还对实现equals和hashCode进行了很好的概述。
回答
对于可变的对象,我们应该"绝不"覆盖equals和getHashCode,这对.net和Java都适用。如果这样做了,并且在f.ex字典中使用这样的对象作为键,然后更改该对象,则会遇到麻烦,因为字典依赖哈希码来找到该对象。
这是一篇有关该主题的好文章:http://weblogs.asp.net/bleroy/archive/2004/12/15/316601.aspx
回答
老实说,在Java中并没有真正反对覆盖相等的论点。如果我们需要比较实例是否相等,那就是我们要做的。
如上所述,我们需要了解与hashCode的约定,并且类似地,在几乎所有我们希望由Comparable定义的自然顺序与equals保持一致的情况下,都要注意Comparable接口周围的陷阱(请参阅BigDecimal API doc(用于规范计数器示例)
除了不使用现有的库类之外,创建一种用于确定相等性的新方法还需要面对Java约定。
回答
@David Schlosnagle提到了乔什·布洛赫(Josh Bloch)的《有效的Java》-这是任何Java开发人员都必须读的书。
有一个相关的问题:对于不可变的值对象,我们还应该考虑覆盖" compare_to"。如果它们不同,则标准措辞在Comparable API中:
It is generally the case, but not strictly required that (compare(x, y)==0) == (x.equals(y)). Generally speaking, any comparator that violates this condition should clearly indicate this fact. The recommended language is "Note: this comparator imposes orderings that are inconsistent with equals."