我遇到的问题是我创建了一个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;
}
}
输出: 假 假 假
答案 0 :(得分:42)
这是因为您的equals()
不是对称:
new Foo("ID1").equals("ID1");
但
"ID1".equals(new Foo("ID1"));
不是真的。这违反了equals()
合同:
equals方法在非null对象引用上实现等价关系:
[...]
对称:对于任何非空引用值
x
和y
,x.equals(y)
应该返回true,当且仅当{{ 1}}返回y.equals(x)
。
它不是反身:
- reflexive :对于任何非空引用值
true
,x
应返回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")));