Java 已排序集合的对象排序

Java Object Ordering for Sorted Collections

当我在看 Java Object Ordering 教程时,文章的最后一节 'Comparators' 让我有点困惑。

通过定义一个 class Employee,它本身可以通过员工姓名进行比较,教程不会显示此 class 是否已覆盖 equals 方法。然后它使用自定义的 Comparator ,其中员工按资历排序,以对员工列表进行排序,我可以理解。

然后教程解释了为什么这不适用于 TreeSet (a SortedSet) 之类的排序集合,原因是:

it generates an ordering that is not compatible with equals. This means that this Comparator equates objects that the equals method does not. In particular, any two employees who were hired on the same date will compare as equal. When you're sorting a List, this doesn't matter; but when you're using the Comparator to order a sorted collection, it's fatal. If you use this Comparator to insert multiple employees hired on the same date into a TreeSet, only the first one will be added to the set; the second will be seen as a duplicate element and will be ignored.

现在我很困惑,因为我知道 List 允许重复元素,而 Set 不基于 equals 方法。所以我想知道当教程说 Comparator 生成的顺序与 equals 不兼容时,这是什么意思?它还说 'If you use this Comparator to insert multiple employees hired on the same date into a TreeSet, only the first one will be added to the set; the second will be seen as a duplicate element and will be ignored.' 我不明白使用 Comparator 会如何影响原始 equals 方法的使用。我认为我的问题是在这种情况下如何生成和排序 TreeSet 以及何时使用 compareequals 方法。

A TreeSet 仅使用比较器来确定两个元素是否 "equal":

https://docs.oracle.com/javase/7/docs/api/java/util/TreeSet.html

Note that the ordering maintained by a set (whether or not an explicit comparator is provided) must be consistent with equals if it is to correctly implement the Set interface. (See Comparable or Comparator for a precise definition of consistent with equals.) This is so because the Set interface is defined in terms of the equals operation, but a TreeSet instance performs all element comparisons using its compareTo (or compare) method, so two elements that are deemed equal by this method are, from the standpoint of the set, equal. The behavior of a set is well-defined even if its ordering is inconsistent with equals; it just fails to obey the general contract of the Set interface.

这意味着当且仅当 equals return 为真时,比较器应该 return 0,以便在 TreeSet 和其他集合之间获得一致的行为,例如 HashSetHashSet 确实使用 equals 和哈希码来确定两个元素是否为 "equal"。

So I wonder when the tutorial says the ordering generated by the Comparator is not compatible with equals, what does it mean?

在此示例中,Comparator 仅根据资历比较两个 Employee 对象。此比较不以任何方式使用 equalshashCode。请记住,当我们将此 Comparator 传递给 TreeSet 时,该集合会将 Comparator 的任何结果 0 视为相等。因此,如果任何 Employee 共享开始日期,则只会添加一个,因为集合认为它们相等。

最后:

I think my question is how the TreeSet will be produced and sorted in this case and when the compare and equals methods are used.

对于TreeSet,如果给定Comparator,它使用compare方法来确定对象的相等性和顺序。如果没有给出 Comparator,则集合使用被排序对象的 compareTo 方法(它们必须实现 Comparable)。

之所以Java规范中声称使用的compare/compareTo方法必须符合equals,是因为Set规范使用 equals,即使这种特定类型的 SetTreeSet 使用比较。

如果您从某个方法实现中收到 Set,您可以预期 equals 方法定义的 Set 中没有重复的对象。但是,由于 TreeSet 不使用此方法,因此开发人员必须小心确保比较方法产生与 equals 相同的相等性。