Java中Set和SortedSet接口之间的逻辑不一致

时间:2013-01-26 07:05:11

标签: java collections set sortedset

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

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

例如:我可以有很多产品,我想按价格对它们进行排序。在这种情况下,SortedSet不能包含具有相同价格的不同产品: [“盐”,0.5 $],[“牛奶”,1 $],[“面包”,1 $],[“香蕉”,2 $] 在上面的例子中,牛奶将被面包取代。在这种情况下,将违反继承的Set接口的合同,因为不相等的对象会相互替换。我更新了SortedSet的JavaDoc并知道这种行为有很好的记录,但我认为这是一个逻辑上的失败。

您有什么看法,也许您已经与Set和SortedSet有类似的问题了?

3 个答案:

答案 0 :(得分: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");

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

答案 1 :(得分:0)

您可能指的是equals()中实际可用的Object方法,因此Java中的每个对象类型都会覆盖它或从Object继承它。

答案 2 :(得分:0)

在Java中,一般来说,如果a,则ba.equals(b) == true两个对象是相同的。 Set,Every Set,甚至SortedSet都没有重复,所以如果你覆盖equals来比较price属性,那么如果两个对象的价格相同,它们是相同的。

我猜您不会覆盖equals方法,但会提供ComparatorSortedSet来进行排序。在这种情况下,如另一个答案所述,如果a.compareTo(b) == 0等同于a.equals(b)

如果您想订购该套装,您需要的是另一种结构,例如进行订购的列表。类似的东西:

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

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