4

我注意到 Java 中 Set 和 SortedSet 接口之间的逻辑不一致。

SortedSet 将不同的对象(通过 equal() 方法)识别为相等,如果它们在比较期间相同,但它在逻辑上是不正确的。对象的比较应该只负责对象的顺序。

例如:我可以有很多产品,我想按价格对它们进行排序。在这种情况下,SortedSet 不能包含价格相同的不同产品:[“salt”,0.5$], [“milk”, 1$], [“bread”, 1$], [“bananas”, 2$ ] 在上面的例子中,牛奶将被面包代替。在这种情况下,继承的 Set 接口的约定将被违反,因为不相等的对象相互替换。我红色了 SortedSet 的 JavaDoc,并且知道这种行为有据可查,但我认为这是一个逻辑上的失败。

你怎么看,也许你已经对 Set 和 SortedSet 有类似的问题?

4

3 回答 3

8

这不是逻辑上的失败,而是设计的属性。请注意,如果您的比较算法与 equals 一致,a.compareTo(b) == 0则将等效于a.equals(b).

javadoc实际上对此非常明确:

一个有序集合的行为是明确定义的,即使它的排序与equals不一致;它只是不遵守 Set 接口的一般约定。

那有用吗?

这实际上在您想要达到特定行为的地方提供了灵活性。例如,假设您想将字符串放入 SortedSet 并忽略大小写对它们进行排序,您可以使用:

Set<String> set = new TreeSet<> (String.CASE_INSENSITIVE_ORDER);

这将达到预期的结果,但是:

set.add("ABC");
set.add("abc");

只会将一个字符串添加到您的集合中,因为它们将被视为与该特定比较器相等。

于 2013-01-26T07:10:47.273 回答
0

在 Java 中,一般来说,两个对象ab是相同的 if a.equals(b) == true。而一个 Set,每个 Set,甚至是 SortedSet,都没有重复项,所以如果你重写equals比较价格属性,如果两个对象具有相同的价格,则它们是相同的。

我猜你不会覆盖equals方法,而是提供一个ComparatortoSortedSet来进行排序。在这种情况下,如另一个答案中所述, ifa.compareTo(b) == 0将等同于a.equals(b).

如果你想订购那个 Set,你需要的是另一个结构,比如一个 List 来进行排序。就像是:

List<Product> list = new ArrayList<Product>(myUnorderedProductsSet);
Collections.sort(list, comparatorByPrice);

请注意,这不会加倍或复制您的 Product Bean,而只是另一个结构,以不同的顺序引用相同的对象。所以不是昂贵的或可以避免的。

于 2013-01-26T07:25:41.850 回答
0

您可能指的equals()是实际可用的方法Object,因此 Java 中的每个对象类型要么覆盖它,要么从Object.

于 2013-01-26T07:08:53.020 回答