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

Java中Set和SortedSet接口之间的逻辑不一致,java,collections,set,sortedset,Java,Collections,Set,Sortedset,我注意到Java中Set和SortedSet接口之间的逻辑不一致 SortedSet将不同对象(通过equal()方法)识别为相等,如果它们在比较过程中相同,但在逻辑上是不正确的。对象的比较只对对象的顺序负责 例如:我可以有很多产品,我想按价格分类。在这种情况下,分拣数据集不能包含相同价格的不同产品: [“盐”,0.5美元],[“牛奶”,1美元],[“面包”,1美元],[“香蕉”,2美元] 在上面的例子中,牛奶将被面包代替。在这种情况下,继承的Set接口的约定将被违反,因为不相等的对象将相互替换

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

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

例如:我可以有很多产品,我想按价格分类。在这种情况下,分拣数据集不能包含相同价格的不同产品: [“盐”,0.5美元],[“牛奶”,1美元],[“面包”,1美元],[“香蕉”,2美元] 在上面的例子中,牛奶将被面包代替。在这种情况下,继承的Set接口的约定将被违反,因为不相等的对象将相互替换。我了解SortedSet的JavaDoc,知道这种行为有很好的文档记录,但我认为这是一个逻辑上的失败


您的看法是什么,可能您已经在Set和SortedSet中遇到了类似的问题?

您可能指的是
equals()
方法,该方法实际上在
对象中可用,因此,Java中的每个对象类型要么重写它,要么从
对象继承它,这不是逻辑上的失败,而是设计上的属性。请注意,如果比较算法与equals一致,
a.compareTo(b)==0
将等同于
a.equals(b)

事实上,这一点非常明确:

即使排序集的顺序与equals不一致,排序集的行为也是定义良好的;它只是没有遵守Set接口的总合同

有用吗?

这实际上为您提供了实现特定行为的灵活性。例如,假设您希望将字符串放入SortedSet并在忽略大小写的情况下对其进行排序,您可以使用:

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

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

在Java中,一般来说,如果
a等于(b)=true,则两个对象
a
b
是相同的。而一个集合,每个集合,甚至SortedSet,都没有重复项,因此如果您覆盖
equals
来比较price属性,那么如果两个对象具有相同的价格,那么它们是相同的

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

如果您想对该集合进行排序,您需要的是另一种结构,如列表以进行排序。比如:

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

请注意,这不会加倍或复制您的产品bean,只会是另一个以不同顺序引用相同对象的结构。因此,这不是昂贵或可以避免的事情。

为什么您认为使用equals()表示相等是不正确的?你说的“不相等的对象相互替换”是什么意思?有时我想按名称对产品进行排序,有时按日期对产品进行排序。如果我直接在Product.equals()方法中实现按价格比较,那么我就不能按日期对产品进行排序。此外,从逻辑上讲,如果产品的价格相同,它们就不相等。那么你需要使用两个不同的比较器。如果你想订购这套产品,你需要的是另一种结构=>我不确定我是否理解你的意思:根据定义,分类数据集是。。。分类。因此无需再次显式排序。如果obj1.equals(obj2)=true,则两个对象是相等的,如果对象相互比较,则两个对象不是相等的。例如,有时我想按名称对产品进行排序,有时则按日期对产品进行排序。如果我直接在product类中实现compare方法并按价格比较产品,那么就无法按日期对产品进行排序。我认为“排序”和“公平”是不同的方面,应该分开。@assylias Yeah集合是排序的,但也没有重复的元素,因为您选择的排序标准只是作为一个集合。您需要另一个结构,它不会保持重复的元素。例如,一个列表。然后你可以保留重复的元素。@thinker我想我知道你的观点,但Java就是不能这样工作。谢谢你的理解,我基于apache集合中的TreeList实现了我的TreeSet版本。它工作得很好,我用ApacheCollection SetTest对它进行了测试。我将在我的开源库的下一个版本中发布它。新的TreeSet不通过comparator将元素识别为equals,而是通过equals()方法将元素识别为equals,并且与normal集合向下兼容。通过这种方式,新的TreeSet实现将包含与HashSet相同的元素,但采用有序的样式。感谢您的回答,有时我想按名称对产品进行排序,有时则按日期对产品进行排序。如果我直接在product类中实现compare方法,并将产品定义为按价格相等,那么我将无法按日期对产品进行排序。我认为“排序”和“公平”是不同的方面,应该分开。这种说法的问题是,实际上没有一种有效的方法来实现将平等与比较分开的数据结构。感谢您的理解,我在apache集合中基于TreeList实现了我的TreeSet版本。它工作得很好,我用ApacheCollection SetTest对它进行了测试。我将在我的开源库的下一个版本中发布它。新的TreeSet不通过comparator将元素识别为equals,而是通过equals()方法将元素识别为equals,并且与normal集合向下兼容。这样,新的TreeSet实现将包含与HashSet相同的元素,但具有有序的样式。
List<Product> list = new ArrayList<Product>(myUnorderedProductsSet);
Collections.sort(list, comparatorByPrice);