Java 包含不同类型集合的对象上的等于

Java 包含不同类型集合的对象上的等于,java,collections,Java,Collections,我有一个类似这样的对象(为了简化equals和hashcode方法,我使用了一些Guava库): 公共类MyClass{ 私有集合整数; 私人收藏字符串; //接球手和接球手。。。 @凌驾 公共布尔等于(对象o){ 如果(o==这个){ 返回true; } 如果(o==null | | getClass()!=o.getClass()){ 返回false; } MyClass that=(MyClass)o; 返回Objects.equal(整数,即.integers)&& Objects.eq

我有一个类似这样的对象(为了简化equals和hashcode方法,我使用了一些Guava库):

公共类MyClass{
私有集合整数;
私人收藏字符串;
//接球手和接球手。。。
@凌驾
公共布尔等于(对象o){
如果(o==这个){
返回true;
}
如果(o==null | | getClass()!=o.getClass()){
返回false;
}
MyClass that=(MyClass)o;
返回Objects.equal(整数,即.integers)&&
Objects.equal(字符串,即.strings);
}
@凌驾
公共int hashCode(){
返回Objects.hashCode(整数、字符串);
}
}
我遇到的问题是基本上实现这一点的代码(这将是一个典型的测试用例):

//生成用户ArrayList列出的MyClass的新实例。
预期的MyClass=新的MyClass();
应为.setinteger(Arrays.asList(1,2,3));
应为.setString(Arrays.asList(“a”、“b”));
//我通常不会在这里构造实际对象,
//但是我已经包含了代码,所以你可以了解发生了什么
//生成使用哈希集的MyClass的新实例。
Set someNumbers=newhashset();
增加(1);
增加(2);
增加(3);
Set someStrings=newhashset();
添加(“a”);
添加(“b”);
MyClass实际值=新的MyClass();
actual.SetInteger(一些数字);
actual.setIntegers(someStrings);
资产质量(预期、实际);
我遇到的问题是,尽管集合的内容都是相同的,并且这些成员的编译时类型是“Collection”,但运行时类型用于计算相等性,因此该断言失败。查看AbstractSet.equals和AbstractList.equals的源代码,他们在计算内容之前分别检查另一个对象是集合还是列表

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


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

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


一种简单的方法是使用将元素转换为数组,使用排序,并使用检查是否相等。不要这样做!对于
集合
,不可能合理地重新定义
等于
,因为它的子类
列表
集合
以不兼容的方式定义它。因此,唯一的可能性是坚持使用从
对象继承的现有
equals
,即测试引用相等性


事实上,你的问题有一个解决方案。。。虽然这更多的是另一个问题而不是解决方案。如果你想考虑<代码>整数<代码>,只要它们等于“代码>列表”(或<代码> SET,你必须选择),你可以通过简单地从<代码> ActuditList(或<代码>抽象集> /代码>)复制相应的方法。
如果您关心的是重复的元素,而不是重复,那么您可以按照amit的建议进行复制。但是,排序需要
可比较的
元素或
比较器
,因此不需要应用。一个非常简单的解决方案是番石榴

然而,像你要求的那样的东西很少出现在一个好的设计中。通常最好是

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

您可以将一个集合的内容复制到
集合中
并比较另一个集合的所有元素是否都存在于
集合中
@LuiggiMendoza它不应该是一个集合,它将考虑两个列表[1,2]和[1,1,2]相等。@阿米特这取决于OP的要求,即一个集合等于另一个集合。我不同意。这不是集合中等号的替代定义,而是他的类中等号的替代定义。@amit:是的,这就是为什么更新我的答案的原因。然而,这样做可能会导致不必要的混乱。
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);