.Contains()方法不调用重写的equals方法
我有一个问题,我创建一个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 fooList = new ArrayList(); 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; } }
输出:false false false
这是因为你的equals()
不对称 :
new Foo("ID1").equals("ID1");
但
"ID1".equals(new Foo("ID1"));
不是真的。 这违反了equals()
合同:
equals方法在非null对象引用上实现等价关系:
[…]
它是对称的 :对于任何非空引用值
x
和y
,当且仅当y.equals(x)
返回true
,x.equals(y)
应返回true
。
这也不是反身 :
- 它是自反的 :对于任何非空引用值
x
,x.equals(x)
应该返回true。
Foo foo = new Foo("ID1"); foo.equals(foo) //false!
@mbockus提供了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()
):
@Override public int hashCode() { return id.hashCode(); }
您的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 – > Generate hashcode()和equals()来等于你…
你应该实现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")));