【问题标题】:LinkedHashSet .equals() vs LinkedList .equals() with same elements but different orderLinkedHashSet .equals() vs LinkedList .equals() 元素相同但顺序不同
【发布时间】:2014-06-11 16:44:57
【问题描述】:

考虑以下 SSCCE:

public static void main(String[] args) {
    LinkedHashSet<String> set1 = new LinkedHashSet<>();
    set1.add("Bob");
    set1.add("Tom");
    set1.add("Sam");
    LinkedHashSet<String> set2 = new LinkedHashSet<>();
    set2.add("Sam");
    set2.add("Bob");
    set2.add("Tom");

    System.out.println(set1);
    System.out.println(set2);
    System.out.println(set1.equals(set2));
}

打印出来:

[Bob, Tom, Sam]
[Sam, Bob, Tom]
true

但是,如果您将 LinkedHashSet 更改为 LinkedList

public static void main(String[] args) {
    LinkedList<String> set1 = new LinkedList<>();
    set1.add("Bob");
    set1.add("Tom");
    set1.add("Sam");
    LinkedList<String> set2 = new LinkedList<>();
    set2.add("Sam");
    set2.add("Bob");
    set2.add("Tom");

    System.out.println(set1);
    System.out.println(set2);
    System.out.println(set1.equals(set2));
}

它产生:

[Bob, Tom, Sam]
[Sam, Bob, Tom]
false

我的问题是澄清问题之一。有人可以帮助理解这一点吗?为什么LinkedHashSet 会被视为相等,而相同的LinkedList 不会?我假设ListSet 的定义起作用,但我不确定。

基本上,我是说如果你认为Sets 是一样的,你会不会认为Lists 也是一样的?反之亦然(假设没有重复元素)?

【问题讨论】:

    标签: java collections linked-list equals linkedhashset


    【解决方案1】:

    LinkedHashSet 做出的保证是关于迭代顺序。但是,它仍然是Set,并且集合本身并不关心顺序。另一方面,List 确实如此。一个元素位于第 3 位的 List 与另一个具有相同元素的 List 不同。

    Set 用于 equals(Object) 方法的 javadoc

    如果指定的对象也是一个集合,则返回true,这两个集合有 大小相同,并且指定集合的​​每个成员都包含在 这个集合(或者等效地,这个集合的每个成员都包含在 指定的集合)。 这个定义确保了equals方法 在 set 接口的不同实现中正常工作。

    LinkedHashSet javadoc 状态

    Set接口的哈希表和链表实现,带有 可预测的迭代顺序。

    LinkedHashSetSet。它具有相同的规则,即。适用于集合 ADT 的那些。

    【讨论】:

    • 但是LinkedHashSet 确实关心顺序,所以它不应该有自己的.equals() 方法来确定顺序相等吗?
    • @ryvantage 该顺序仅用于迭代,不适用于Set 所代表的内容。而且,不,它没有自己的equals 方法。它继承自AbstractSet
    • 我想我的问题更像是一个为什么的问题。 “这个定义确保了 equals 方法在 set 接口的不同实现中正常工作。”那部分真的很有帮助。 Set 的每个实现都必须具有相同的标准。不过,我仍然不确定为什么,但很明显 LHS 只是遵循Set equals 定义中设定的标准。在我看来,两个具有不同排序的LinkedHashSets 并不相等,这仍然是合乎逻辑的。只有我一个人吗?
    • @ryvantage 这些类是ADTs 的实现。集合就是这样一种数据结构。它被定义为an abstract data structure that can store certain values, without any particular order, and no repeated values. 换句话说,顺序对集合并不重要。 LinkedHashSet 中的顺序只对程序员很重要,不会脱离集合数据结构的定义。
    • @ryvantage 从另一边看。如果您依赖的库具有返回 Set 的 API,并且您将该库的一些补丁应用到您的应用程序中,该补丁应该是内部错误修复,并且您的应用程序崩溃并烧毁,因为开发人员更改了下面的实现出于内部原因的引擎盖……这对你来说似乎合乎逻辑吗? :)
    【解决方案2】:

    如上所述: LinkedHashSet 扩展 HashSet 扩展 AbstractSet 实现 equals 方法:https://docs.oracle.com/javase/8/docs/api/java/util/AbstractSet.html#equals-java.lang.Object-

    比较指定对象与此集合是否相等。如果给定对象也是一个集合,则返回 true,这两个集合具有相同的大小,并且给定集合的每个成员都包含在该集合中。这可确保 equals 方法在 Set 接口的不同实现中正常工作。

    如果顺序对您很重要,比较 LinkedHashSet 的最简单方法是将其序列化并进行比较:

        LinkedHashSet<Integer> reverseOrder = new LinkedHashSet<>();
        reverseOrder.add(2);
        reverseOrder.add(1);
        LinkedHashSet<Integer> ordered = new LinkedHashSet<>();
        ordered.add(1);
        ordered.add(2);
        System.out.println("Equals via set: " + ordered.equals(reverseOrder));
        System.out.println("Equals With Arrays: " + ordered.ordered.toString().equals(reverseOrder.ordered.toString()));
    

    结果:

    Equals via Set: true
    Equals With Arrays: false
    

    【讨论】:

    • toArray 方法无论如何都会返回一个新数组,对于数组,equal 方法会检查 reference 相等性 - 所以代码 sn-p 并没有真正使感觉(即即使两个集合中的顺序是相同,那么第二个输出仍然是false ...)
    • Marco13 好点,改为序列化两个列表然后比较。
    猜你喜欢
    • 2019-06-12
    • 2023-03-29
    • 2013-07-29
    • 1970-01-01
    • 2021-03-06
    • 1970-01-01
    • 2011-04-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多