Java SortedSet + Comparator,与equals()问题的一致性

时间:2009-10-02 16:10:32

标签: java equals comparator sortedset

我希望有一个SortedSet of Collections(在这种情况下设置自己,但不一定是一般),按Collection大小排序。这似乎违反了使比较器与equals()一致的禁止 - 即两个集合可能不相等(通过具有不同的元素),但是与相同的值相比(因为它们具有相同数量的元素)。

从理论上讲,我也可以通过比较器的方式对相同大小的组进行排序,但是使用排序不会利用它,并且没有真正有用的+直观的方法来比较相同大小的集合(至少,在我的特定情况下),所以这似乎是浪费。

这种不一致的情况是否有问题?

5 个答案:

答案 0 :(得分:8)

SortedSet接口扩展了核心Set,因此应符合Set规范中列出的合同。

实现这一目标的唯一可能方法是让元素的equal()方法行为与您的Comparator保持一致 - 原因是核心Set基于相等而运行{ {1}}基于比较运作。

例如,核心Set接口中定义的add()方法指定如果已经有一个元素的SortedSet方法将返回true,并且此新元素为,则无法向该元素添加元素论点。好吧,equal()不使用SortedSet,它使用equal()。因此,如果compareTo()返回compareTo(),即使false要返回equals(),也会添加您的元素,从而违反了true合同。

然而,这些都不是实用问题。 Set行为始终保持一致,即使SortedSetcompare()不相同。

答案 1 :(得分:3)

正如ChssPly76在评论中所写,在两个集合具有相同大小但不相等的情况下,您可以使用hashCode来决定compareTo调用。这种方法很好,除了极少数情况下,你有两个具有相同大小的集合,不相等,但具有相同的hashCode。不可否认,这种情况发生的可能性非常小,但可以想象。如果你想要非常小心,而不是hashCode,请使用System.identityHashCode。这应该为每个Collection提供一个唯一的编号,并且不应该发生冲突。

在一天结束时,这为您提供了按照大小排序的集合中的集合的功能,在两个具有匹配大小的集合的情况下具有任意顺序。如果这就是你所需要的,它并不比通常的比较慢。如果您需要在不同的JVM实例之间保持一致的顺序,这将无法工作,您将不得不以其他方式执行此操作。

伪代码:

if (a.equals(b)) {
    return 0;
} else if (a.size() > b.size()) {
    return 1;
} else if (b.size() > a.size()) {
    return -1;
} else {
    return System.identityHashCode(a) > System.identityHashCode(b) ? 1 : -1;
}

答案 2 :(得分:3)

  

这似乎违反了禁令   让比较器保持一致   with equals() - 即两个集合   可能是不平等的(通过不同的   元素),但比较相同   价值(因为他们有相同的   元素数量。)

没有要求(在Javadoc中)或暗示,Comparator与对象的boolean equals(Object)实现一致。

请注意,ComparableComparator不同的接口,目的不同。 Comparable用于定义类的“自然”顺序。在这种情况下,equalscompateTo不一致是个坏主意。相比之下,当您想要使用与类的自然顺序不同的顺序时,使用Comparator

编辑:这是来自Javadoc for SortedSet的完整段落。

  

注意由a维护的排序   排序集(无论是否明确   提供比较器)必须   如果排序,则与equals一致   set是为了正确实现Set   接口。 (见比较   接口或比较器接口   一致的精确定义   等于。)这是因为   设置接口是根据定义的   等于操作,但有一个排序   set执行所有元素比较   使用compareTo(或比较)   方法,所以两个元素   通过这种方法认为是平等的   排序集的立场,   等于。 有序集的行为是   定义明确,即使它的排序是   与平等不一致;它只是   没有遵守总的合同   设置界面。

我突出了最后一句话。关键是这样的SortedSet会像你最想要的那样工作,但是某些操作的行为与Set规范不完全匹配......因为规范根据{{1}来定义它们的行为方法。

所以事实上,一致的声明要求(我的错误),但忽略它的后果并不像你想象的那么糟糕。当然,要决定是否应该这样做。在我的估计中,它应该没问题,只要你彻底评论代码并确保SortedSet不会“泄漏”。

但是,从语义的角度来看,我不清楚只关注集合“大小”的集合的比较器才能起作用。我的意思是,你真的想说所有与(比方说)2个元素的集合是相同的吗?这意味着您的集合只能包含任何给定大小的一个集合......

答案 3 :(得分:1)

Comparator没有理由返回与equals()相同的结果。实际上,引入了Comparator API,因为equals()还不够:如果要对集合进行排序,则必须知道两个元素是否更小或更大。

答案 4 :(得分:0)

作为标准API的一部分,SortedSet打破了Set接口中定义的契约并使用Comparator来定义相等而不是equals方法,这有点奇怪。但就是这样。

如果您的实际问题是根据包含的集合的大小对集合集合进行排序,那么您最好使用List,您可以使用Collections.sort(List,Comparator>)对其进行排序;