1

我想要一个按集合大小排序的集合的 SortedSet(在这种情况下是集合本身,但不一定是一般情况)。这似乎违反了让 Comparator 与 equals() 一致的禁令——即,两个集合可能不相等(通过具有不同的元素),但比较相同的值(因为它们具有相同数量的元素)。

从概念上讲,我也可以使用比较器方法对大小相等的集合进行排序,但是使用排序不会利用这一点,并且没有真正有用+直观的方法来比较大小相等的集合(至少,在我的特殊情况下),所以这似乎是一种浪费。

这种不一致的情况似乎是个问题吗?

4

5 回答 5

8

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

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

例如,核心 Set 接口中定义的方法指定如果已经有一个元素的方法将返回 true 并将这个新元素作为参数add(),则您不能将元素添加到集合中。equal()好吧,SortedSet不使用equal(),它使用compareTo()。因此,如果您的compareTo()退货,false即使equals()要退货,您的元素也会被添加true,从而违反Set合同。

然而,这些都不是一个实际问题。SortedSet行为总是一致的,即使compare()vsequals()不是。

于 2009-10-02T16:50:58.863 回答
4

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

归根结底,这为您提供了让集合中的集合按大小排序的功能,在两个大小匹配的集合的情况下可以任意排序。如果这就是您所需要的,它不会比通常的比较慢多少。如果您需要不同 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;
}
于 2009-10-02T21:24:02.900 回答
3

这似乎违反了让 Comparator 与 equals() 一致的禁令——即,两个集合可能不相等(通过具有不同的元素),但比较相同的值(因为它们具有相同数量的元素)。

无论是声明(在 Javadoc 中)还是暗示,都没有要求 aComparator与对象的boolean equals(Object).

请注意,ComparableComparator是具有不同用途 的不同接口。Comparable用于定义类的“自然”顺序。equals在这种情况下,不一致和不一致将是一个坏主意compateTo。相反,Comparator当您想要使用与类的自然顺序不同的顺序时,使用 a。

编辑:这是 SortedSet 的 Javadoc 中的完整段落。

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

我已经强调了最后一句话。关键是这样的 SortedSet 将按照您的预期工作,但某些操作的行为不会完全符合Set规范……因为规范根据方法定义了它们的行为equals

所以事实上,对一致性有一个明确的要求(我的错误),但是忽略它的后果并没有你想象的那么糟糕。当然,这取决于你是否应该这样做。我估计应该没问题,只要您彻底注释代码并确保 SortedSet 不会“泄漏”。

但是,我不清楚仅查看集合“大小”的集合比较器是否会起作用……从语义的角度来看。我的意思是,你真的想说所有(比如说)2 个元素的集合都是平等的吗?这意味着您的集合只能包含一个任何给定大小的集合......

于 2009-10-03T02:05:06.653 回答
1

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

于 2009-10-02T16:15:50.137 回答
0

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

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

于 2009-10-02T17:10:08.033 回答