在Java中实现Comparator接口时,是否需要重写equals方法?如果我不这样做,java编译器不会抱怨。但这样做可以吗?
答案 0 :(得分:2)
Comparator<T>
是一个有助于比较T
类型的两个对象的对象。您需要实现的唯一方法是compare(o1, o2)
。它指定了类T
的对象的排序。
这不需要重写equals方法,但是对于一致性(和逻辑),如果比较器compare()
方法在比较两个对象0
和o1
时返回o2
,o1.equals(o2)
和o2.equals(o1)
应该返回true。
Javadoc:Comparator
答案 1 :(得分:2)
Comparator<SomeClass>
接口是作为SomeClass
类的单独类实现的。 SomeClass.equals(Object)
不需要与比较器保持一致。 (实际上,它几乎会破坏拥有单独比较器对象的目的!)
另一方面,如果SomeClass
实施Comparable<SomeClass>
,则强烈建议 equals(Object)
和compare(SomeClass, SomeClass)
保持一致。 Comparable
的javadoc说:
“强烈建议(尽管不要求)自然排序与equals一致。这是因为没有显式比较器的有序集(和有序映射)在与元素一起使用时表现得”奇怪“(或其自然顺序与equals不一致。特别是,这样的有序集(或有序映射)违反了set(或map)的一般契约,它是根据equals方法定义的。“
“例如,如果将两个键a和b添加到
(!a.equals(b) && a.compareTo(b) == 0)
到不使用显式比较器的有序集,则第二个add操作返回false(以及已排序的大小) set不会增加)因为a和b在排序集的视角中是等价的。“
如果我不这样做,java编译器就不会抱怨。
Java编译器无法确定equals
和compare
是否一致。 (或者equals
和hashcode
就此而言。)理论上,在所有情况下都不可能做到这一点,并且在实践中超越了“最新技术”。在某些情况下,您覆盖equals
的简单测试会给出错误警告。
您不能依赖编译器来指出应用程序中的逻辑错误。
如果问题实际上是关于Comparable<T>.equals(Object)
的语义,那么答案就在javadocs中:
“请注意,不要覆盖Object.equals(Object)总是安全的。但是,在某些情况下,通过允许程序确定两个不同的比较器强加相同的顺序,覆盖此方法可以提高性能。 “
Ted Hopp因此评论道:
“实际上,比较器对于排序是有用的;没有理由让它与equals()一致”会破坏目的“。通常,使它们保持一致是个好主意,尽管这不是必需的。”
首先,特德误解了我所写的内容。我说:
“它......”(即T.equals(Object)和Comparator.compare(T,T)之间的一致性的假设要求` “......会破坏单独的比较器”的目的
其次,比较器与平等一致并不是一个好主意或坏主意。它完全取决于equals的预期语义,以及比较器的预期目的。
如果比较器用于对TreeSet中的元素进行排序,那么与equals
的不一致将导致奇怪的行为。
如果比较器用于排序对象列表以供显示,那么与equals
的一致性可能无关紧要。
答案 2 :(得分:2)
The JavaDoc for this method in the Comparator Interface说:“请注意,不要覆盖Object.equals(Object)总是安全的。但是,在某些情况下,覆盖此方法可以通过允许程序确定两个不同的比较器强加来提高性能同样的顺序。“
具体来说,请注意equals()
方法用于将不同的Comparator与Comparator的实现进行比较,而不是检查模板类型的两个对象是否相等。