【问题标题】:equals on objects that contain different types of collections等于包含不同类型集合的对象
【发布时间】:2014-04-28 21:30:32
【问题描述】:

我有一个看起来像这样的对象(我使用了一些 Guava 库来简化我的 equals 和 hashcode 方法):

public class MyClass {
    private Collection<Integer> integers;
    private Collection<String> strings;

    // Getters and Setters...

    @Override
    public boolean equals(Object o) {
        if (o == this) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        MyClass that = (MyClass) o;

        return Objects.equal(integers, that.integers) &&
               Objects.equal(strings, that.strings);
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(integers, strings);
    }
}

我遇到的问题是基本上执行此操作的代码(这将是一个典型的测试用例):

// Produce a new instance of MyClass that users ArrayLists.
MyClass expected = new MyClass();
expected.setIntegers(Arrays.asList(1, 2, 3));
expected.setStrings(Arrays.asList("a", "b"));

// I don't normally construct the actual object here, 
// but I've included the code so you get an understanding of what's happening

// Produce a new instance of MyClass that uses HashSets.
Set<Integer> someNumbers = new HashSet<Integer>();
someNumbers.add(1);
someNumbers.add(2);
someNumbers.add(3);
Set<String> someStrings = new HashSet<String>();
someStrings.add("a");
someStrings.add("b");
MyClass actual = new MyClass();
actual.setIntegers(someNumbers);
actual.setIntegers(someStrings);

assertEquals(expected, actual);

我遇到的问题是,即使集合的内容都是相同的,并且这些成员的编译时类型是“集合”,运行时类型用于评估相等性,所以这个断言失败。查看 AbstractSet.equals 和 AbstractList.equals 的源代码,他们在评估内容之前分别检查另一个对象是 Set 还是 List。

我认为这是有道理的,因为顺序在列表中很重要,而在集合中不重要,因此,即使内容相同,您也无法比较它们。

也就是说,在这种情况下,我不关心底层集合是什么 - 我只想知道内容是否相同并且顺序没有区别。有什么简单的方法吗?

【问题讨论】:

  • 您可以将一个集合的内容复制到Set&lt;OtherClass&gt; 中,然后比较另一个集合的所有元素是否都存在于Set 中。
  • @LuiggiMendoza 它不应该是一个集合,它会将两个列表 [1,2] 和 [1,1,2] 视为相等。
  • @amit 这取决于 OP 的要求,即一个集合等于另一个集合。

标签: java collections


【解决方案1】:

如果底层集合对您来说不重要,您可以切换到一个允许重复的预定义有序集合,确保两个新集合已排序,然后检查是否相等。

一种简单的方法是使用toArray() 将元素转换为数组,使用Arrays.sort() 对其进行排序,然后使用Arrays.equals() 检查是否相等

【讨论】:

    【解决方案2】:

    只是不要这样做!不可能为 Collection 重新定义 equals,因为它的子类 ListSet 以不兼容的方式定义它。所以唯一的可能是坚持现有的equals继承自Object,即测试引用相等性。


    实际上,您的问题有一个解决方案......虽然它更多的是另一个问题而不是解决方案。如果你想考虑integers等于List(或Set,你必须选择),你可以通过简单地从AbstractList(或AbstractSet)复制循环来编写相应的方法)。


    如果您关心重复的元素,但不关心重复,您可以按照 amit 的建议进行排序。但是,排序需要Comparable 元素或Comparator,因此不需要。一个非常简单的解决方案是 Guava 的Multiset

    但是,像您所要求的那样的事情很少出现在好的设计中。通常最好是

    • 放下二传手
    • 添加类似 setter 的方法,将内容复制到所需的具体集合中

    【讨论】:

    • 我不同意。这不是集合相等的替代定义,而是 HIS CLASS 的替代定义。
    • @amit:是的,这是真的,这就是为什么更新我的答案。但是,这样做可能会导致不必要的混乱。
    猜你喜欢
    • 2013-05-27
    • 1970-01-01
    • 2011-11-21
    • 2017-06-13
    • 2011-04-02
    • 1970-01-01
    • 1970-01-01
    • 2013-08-29
    • 2011-05-17
    相关资源
    最近更新 更多