【问题标题】:Why Comparable natural ordering needs to be consistent with equals method?为什么 Comparable 自然排序需要与 equals 方法一致?
【发布时间】:2013-08-18 18:18:18
【问题描述】:

假期后回来 :) 带着问题。我正在阅读 Comparable interface documentation from ComparableDocumentation。我确实理解,我们使用可比较的,因为它将为我们提供排序和自然排序。在文档中是这样写的。

强烈建议(尽管不是必需的)自然 排序与equals一致。之所以如此,是因为排序集 (和排序的地图)没有显式比较器的行为“奇怪”时 它们与自然顺序为的元素(或键)一起使用 与等号不一致。特别是,这样的排序集(或排序 map) 违反了 set(或 map)的一般约定,该约定被定义为 就equals方法而言。

Comparable 与 equals 有什么关系。 Comparable 有 compareTo 方法,为什么需要和 equals 方法保持一致?我无法理解这个概念。

也引用了来源,有人也可以详细说明这一点

例如,如果添加两个键 a 和 b 使得 (!a.equals(b) && a.compareTo(b) == 0) 到不使用显式的排序集 比较器,第二个加法操作返回假(和大小 排序集不会增加),因为 a 和 b 等价于 排序集的视角。

谢谢。

【问题讨论】:

    标签: java generics collections


    【解决方案1】:

    compareTo 返回 0 的语义是两个对象,嗯,相等。在另一种方法中对相同关系进行另一种定义显然会导致多种麻烦,正如您的引用中所记录的那样:SortedSet 实现中的典型算法依赖于compareTo,但@987654324 的一般合同@interface 指定它不能包含两个对象equals。来自compareToequals 的报告不一致会导致这种情况。

    【讨论】:

    • 非常感谢。我现在明白了这个概念。意思是Set接口使用equals方法促进相等比较?
    • 是的,因为典型的Set 实现并不关心其元素的任何顺序:它只关心它们都是不同的。 equals 的主要作用可以说是让Sets 工作。
    • 非常感谢。我现在明白了这个概念。非常感谢。
    • @benz :既然是 Marko 的回答对你有帮助,你应该接受它:)。
    • 你的第二句话完全是关于我在回答中已经解释过的内容,只是用了不同的、更正式的表达方式。
    【解决方案2】:

    简答:只要compareTo(a,b) 为两个对象ab 返回0a.equals(b)b.equals(a) 就应该是true,反之亦然。

    长答案:如Comparable 文档中所述,Comparable 的实现强制执行总排序。 properties of total ordering 之一是“反对称”:如果我们定义一个全序≤,那么:

    如果 a ≤ b 且 b ≤ a 则 a = b

    这表示为compareTo()0 返回值。

    您引用的文本中提到的方法和类利用了此特征,以实现更正确和更有效的行为。

    【讨论】:

    • 我正在编辑问题以提出另一个造成混乱的观点。
    • 我完全理解你们描述的概念。非常感谢你。你能看到我编辑的问题并告诉我为什么第二个添加到 sortedset 中。
    • @benz :和 Marko 一样,我不确定这里有什么不清楚的地方。您确实注意到它是!a.equals(b),而不是a.equals(b)?如果是这样,请进一步编辑您的问题,以说明您对该陈述的不理解之处。
    • 我正在剖析声明。条件意味着如果 a 和 b 不是相等的对象并且它们的比较操作返回 0,则添加到集合中。我很困惑的是,为什么第二次添加操作不会让他们添加并且大小不会增加。这句话让我很困惑。
    • @benz :因为 Java Set 像数学集合一样工作 - 它包含 distinct 对象。因此,如果您已经添加了一个对象 a 并且您稍后尝试添加和对象 b 这被认为是“相同的”(至少由equals() ),那么该操作将不会做任何事情,因为,就集合而言,b 已经在集合中,因为它与a“相同”
    【解决方案3】:

    您可以在 Set 的文档中看到它:

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

    【讨论】:

    • 我想知道让TreeSet 支持“无序项”节点类型需要多少成本,比如将一个项目添加到已经包含 compareTo 产生零的项目的树中但是equals 返回false 将创建一个包含新旧项目的“无序项目”节点,并且遇到“无序项目”节点的搜索将搜索两个分支。这将允许这种类型的行为与普通的 Set 一样,尽管它只有在大多数项目都可以按等级区分时才能有效地执行。
    猜你喜欢
    • 2015-01-02
    • 1970-01-01
    • 2019-01-22
    • 1970-01-01
    相关资源
    最近更新 更多