Java的比较合同

时间:2014-04-07 10:27:47

标签: java collections comparator

它在Comparator接口的合同中说,它必须与equals一致。

如果equalsTo = true,这是否意味着Comparator = 0,或者如果并且仅当 equalsTo = true时它是否意味着Comparator = 0?

我似乎记得它是第二个,但我遇到了许多按非唯一子属性排序的比较器。

例如,我可能有对象具有子属性日期,我想按提交日期对对象列表进行排序。但是,您可以使用相同日期的多个对象?这有什么后果?当然这个问题已经有了最佳实践解决方案吗?如何在没有违反比较合同的情况下对属性进行排序,并且不保证是唯一的?这种违规行为会带来什么后果?它们可以管理吗?

5 个答案:

答案 0 :(得分:6)

比较器必须与equals保持一致,这一点都不是真的。

文档只是警告这种情况:

  

当使用能够强加与equals不一致的排序的比较器来排序有序集(或有序映射)时,应该小心(http://docs.oracle.com/javase/7/docs/api/java/util/Comparator.html

如果你有一个基于日期的订购,另一个基于日期+时间的订购,你应该简单地实现多个比较器。

也许你比较Comparator和Comparable?对于Comparable,文档强烈反对这种情况:

  

强烈建议(尽管不要求)自然排序与equals一致。 (http://docs.oracle.com/javase/7/docs/api/java/lang/Comparable.html

如果你意识到一个对象只能有一个Comparable的实现,但是Comparator的多个实现,那么这种差异是有意义的。比较器的整个想法是有多种方法来比较同一个类。

答案 1 :(得分:2)

编辑 您可以拥有多个Comparators,而 popovitsj 表示他们不一定要与之保持一致equals

(虽然我假设大部分时间都有Comparator.compare(obj1, obj2) == 0< => obj1.equals(obj2) == true

如果您希望在按非唯一字段排序时获得特定的排序结果,则需要自定义Comparator以解决这些问题,

例如,在实施compare()时,您会遇到obj1.date == obj2.date,那么您应该将其他重要字段(姓名,年龄等)与obj1obj2进行比较并返回相应的值。

希望有所帮助。

答案 2 :(得分:0)

正如您所怀疑的,为了使compareTo()equals()保持一致,compareTo()必须始终0时返回equals() }返回true。同样,如果equals返回false,则compareTo 不得返回0

然而,正如popovitsj在他的回答中指出的那样,equals()的一致性不是一个要求。因此,上述内容仅适用于您尝试使两种方法保持一致的情况。

答案 3 :(得分:0)

  

它在Comparator接口的合同中说,它必须与equals一致。

这不完全正确;请参阅@popovitjs的回答。

  

如果equalsTo = true,这是否意味着Comparator = 0,或者当且仅当equalsTo = true时,它是否意味着Comparator = 0?

这意味着后者。但是,它实际上并不是Comparator个对象的硬性要求。

  

我似乎记得它是第二个,但我遇到了许多按非唯一子属性排序的比较器。

这是合理的,因为它实际上并不是一项艰难的要求。事实上,如果您要将其与Comparator一起使用,那么与equals(Object)不一致的Arrays.sort(...)就可以了。问题仅出现在TreeSetTreeMap

例如,假设您有Comparator<E> C表示e1e2不相等,但e1.equals(e2)返回true。现在假设您使用比较器创建TreeSet<E>实例,然后将e1e2添加到该集合中。集合的树基于比较器进行组织,因此e1e2将插入搜索树中的不同位置,并且都将成为集合的元素。但违反 Set的主要不变量...基于equals方法。

正如TreeSet的javadoc所说:

  

“请注意,如果要正确实现Set接口,则由一个集合维护的排序(无论是否提供显式比较器)必须与equals一致。(请参阅Comparable或Comparator以获得精确定义与equals一致。)这是因为Set接口是根据equals操作定义的,但TreeSet实例使用compareTo(或compare)方法执行所有元素比较,因此这个方法认为相同的两个元素是,从集合的角度看,相等。集合的行为即使其排序与equals不一致也是明确定义的;它只是不遵守Set接口的一般契约。“

这回答了你问题的最后部分。

  

此类违规会产生什么后果?

如果在TreeSet或TreeMap中使用不一致的Comparator,则该集合将不遵守SetMap合同。

答案 4 :(得分:-1)

a b 可能不相等。但是,如果在比较 a b 时比较器为零,则在比较 b a 时应该为零。

this answer中说:

  

通常,如果2个对象从等于透视图相等但不是从compareTo透视图中等于,则可以将这两个对象作为键存储在TreeMap中。这可能导致不直观的行为。它也可以在特定情况下有目的地完成。

但这是针对特定情况通常没有什么可以阻止你在等于和compareTo行为不一致时出现不一致的行为。

一个例子,今天早上有人问:Move specific items to the end of a list

大多数答案的比较器对于不相等的元素返回0。