【问题标题】:Java Object Ordering for Sorted Collections有序集合的 Java 对象排序
【发布时间】:2016-06-20 14:50:00
【问题描述】:

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

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

然后教程解释了为什么这对于诸如TreeSetSortedSet)这样的排序集合不起作用,原因是:

它会生成一个与 equals 不兼容的排序。这意味着此 Comparator 等同于 equals 方法不等同的对象。特别是,在同一日期雇用的任何两名员工都将进行比较。当您对列表进行排序时,这无关紧要;但是当您使用 Comparator 来订购排序的集合时,这是致命的。如果您使用此比较器将同一日期雇用的多个员工插入 TreeSet,则只会将第一个添加到集合中;第二个将被视为重复元素并被忽略。

现在我很困惑,因为我知道 List 允许重复元素,而 Set 不基于 equals 方法。所以我想知道当教程说Comparator生成的排序与equals不兼容时,这是什么意思?它还说'如果您使用此比较器将同一日期雇用的多个员工插入 TreeSet,则只会将第一个添加到集合中;第二个将被视为重复元素并将被忽略。我不明白使用Comparator 将如何影响原始equals 方法的使用。我想我的问题是TreeSet 在这种情况下将如何生成和排序,以及何时使用compareequals 方法。

【问题讨论】:

    标签: java collections treeset


    【解决方案1】:

    所以我想知道当教程说Comparator生成的排序与equals不兼容时,这是什么意思?

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

    最后:

    我想我的问题是在这种情况下如何生成和排序 TreeSet 以及何时使用 compare 和 equals 方法。

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

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

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

    【讨论】:

    • 谢谢!现在我明白这是为了使其与Set 接口保持一致,我看到像contains() 这样的方法使用equals 方法。
    【解决方案2】:

    TreeSet 仅使用比较器来确定两个元素是否“相等”:

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

    请注意,如果要正确实现 Set 接口,集合维护的顺序(无论是否提供显式比较器)必须与 equals 一致。 (参见 Comparable 或 Comparator 以了解与 equals 一致的精确定义。)这是因为 Set 接口是根据 equals 操作定义的,但 TreeSet 实例使用其 compareTo(或 compare)方法执行所有元素比较,所以两个从集合的角度来看,这种方法认为相等的元素是相等的。 集合的行为是明确定义的,即使它的顺序与equals不一致;它只是不遵守 Set 接口的一般约定。

    这意味着当且仅当 equals 返回 true 时 Comparator 应该返回 0,以在 TreeSet 和其他集合之间获得一致的行为,例如 HashSetHashSet 确实使用equals 和哈希码来确定两个元素是否“相等”。

    【讨论】:

    • 直到 Zircon 详细说明,我才完全得到您的答案。尽管如此,还是非常感谢你。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-20
    • 2018-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-23
    相关资源
    最近更新 更多