我希望有一个SortedSet of Collections(在这种情况下设置自己,但不一定是一般),按Collection大小排序。这似乎违反了使比较器与equals()一致的禁止 - 即两个集合可能不相等(通过具有不同的元素),但是与相同的值相比(因为它们具有相同数量的元素)。
从理论上讲,我也可以通过比较器的方式对相同大小的组进行排序,但是使用排序不会利用它,并且没有真正有用的+直观的方法来比较相同大小的集合(至少,在我的特定情况下),所以这似乎是浪费。
这种不一致的情况是否有问题?
答案 0 :(得分:8)
SortedSet
接口扩展了核心Set
,因此应符合Set
规范中列出的合同。
实现这一目标的唯一可能方法是让元素的equal()
方法行为与您的Comparator
保持一致 - 原因是核心Set
基于相等而运行{ {1}}基于比较运作。
例如,核心Set接口中定义的add()
方法指定如果已经有一个元素的SortedSet
方法将返回true,并且此新元素为,则无法向该元素添加元素论点。好吧,equal()
不使用SortedSet
,它使用equal()
。因此,如果compareTo()
返回compareTo()
,即使false
要返回equals()
,也会添加您的元素,从而违反了true
合同。
然而,这些都不是实用问题。 Set
行为始终保持一致,即使SortedSet
与compare()
不相同。
答案 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)
实现一致。
请注意,Comparable
和Comparator
是不同的接口,目的不同。 Comparable
用于定义类的“自然”顺序。在这种情况下,equals
和compateTo
不一致是个坏主意。相比之下,当您想要使用与类的自然顺序不同的顺序时,使用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>)对其进行排序;