.Contains()方法不调用重写的equals方法

时间:2012-02-16 20:55:04

标签: java equals contains

我遇到的问题是我创建了一个Foo对象的ArrayList,我重写了equals方法,而且我无法获得contains方法来调用equals方法。我已经尝试重写equals和hashcode,但它仍然无法正常工作。我敢肯定有一个合乎逻辑的解释,为什么会这样,但我现在无法弄清楚我自己大声笑。我想要一种方法来查看列表是否包含指定的id。

以下是一些代码:

import java.util.ArrayList;
import java.util.List;

public class Foo {

    private String id;


    public static void main(String... args){
        Foo a = new Foo("ID1");
        Foo b = new Foo("ID2");
        Foo c = new Foo("ID3");
        List<Foo> fooList = new ArrayList<Foo>();
        fooList.add(a);
        fooList.add(b);
        fooList.add(c);
        System.out.println(fooList.contains("ID1"));
        System.out.println(fooList.contains("ID2"));
        System.out.println(fooList.contains("ID5"));
    }   

    public Foo(String id){
        this.id = id;
    }

    @Override
    public boolean equals(Object o){
        if(o instanceof String){
            String toCompare = (String) o;
            return id.equals(toCompare);
        }
        return false;
    }



    @Override
    public int hashCode(){
        return 1;
    }
}

输出: 假 假 假

3 个答案:

答案 0 :(得分:42)

这是因为您的equals()不是对称

new Foo("ID1").equals("ID1");

"ID1".equals(new Foo("ID1"));

不是真的。这违反了equals()合同:

  

equals方法在非null对象引用上实现等价关系:

     
      
  • [...]

  •   
  • 对称:对于任何非空引用值xyx.equals(y)应该返回true,当且仅当{{ 1}}返回y.equals(x)

  •   

它不是反身

  
      
  • reflexive :对于任何非空引用值truex应返回true。
  •   
x.equals(x)

@mbockus 提供Foo foo = new Foo("ID1"); foo.equals(foo) //false! 的正确实现:

equals()

但现在您必须将public boolean equals(Object o){ if(o instanceof Foo){ Foo toCompare = (Foo) o; return this.id.equals(toCompare.id); } return false; } 的实例传递给Foo

contains()

最后,您应该实现System.out.println(fooList.contains(new Foo("ID1"))); System.out.println(fooList.contains(new Foo("ID2"))); System.out.println(fooList.contains(new Foo("ID5"))); 以提供一致的结果(如果两个对象相等,它们必须具有相同的hashCode()):

hashCode()

答案 1 :(得分:11)

您的equals方法需要更改并覆盖hashCode()函数。目前,当您需要检查Foo对象时,您正在检查您要比较的对象是否是String的实例。

public boolean equals(Object o){
    if(o instanceof Foo){
        Foo toCompare = (Foo) o;
        return this.id.equals(toCompare.id);
    }
    return false;
}

如果您正在使用Eclipse,我建议让Eclipse生成hashCode,并通过转到Source来获取等于 - &gt;生成hashcode()和equals()...

答案 2 :(得分:5)

你应该实现hashCode

@Override
public int hashCode() {
    return id.hashCode();
}

即使包含在没有它的ArrayList中也适用。你的大问题是你的equals需要String,而不是Foo对象以及你要求包含字符串。如果实现询问列表中的每个弹出是否等于你发送的字符串,那么你的代码可以工作,但是实现会询问字符串是否等于你的Foo目标,当然不是。

使用等于

@Override
public boolean equals(Object o){
    if(o instanceof Foo){
        String toCompare = ((Foo) o).id;
        return id.equals(toCompare);
    }
    return false;
}

然后检查包含

System.out.println(fooList.contains(new Foo("ID1")));