.Contains() 方法不调用 Overridden equals 方法
Posted
技术标签:
【中文标题】.Contains() 方法不调用 Overridden equals 方法【英文标题】:.Contains() method not calling Overridden equals method 【发布时间】:2012-03-08 07:14:04 【问题描述】:我有一个问题,我创建了一个 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;
输出: 错误的 错误的 假的
【问题讨论】:
你为什么要检查愚蠢的包含一个字符串? 大约 9 年前我问过这个问题。我现在知道这没有意义,但当时我不明白。感谢这个问题的答案,我现在了解 .equals() 的工作原理。 【参考方案1】:这是因为您的equals()
不是对称:
new Foo("ID1").equals("ID1");
但是
"ID1".equals(new Foo("ID1"));
不正确。这违反了equals()
合约:
equals 方法在非空对象引用上实现等价关系:
[...]
它是对称的:对于任何非空引用值
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();
【讨论】:
@ReidMac:我错了,这是关于equals()
不是对称的,看看我的编辑。 hashCode()
在这种情况下没有任何关系,但你还是要遵循这个原则
奇怪的是我们需要使用这个new Foo("ID1");
约定来使用自定义的equals方法。这背后有什么原因吗?【参考方案2】:
您的 equals 方法需要随着覆盖 hashCode() 函数而改变。目前,当您需要检查 Foo 对象时,您正在检查您要比较的对象是否为 instanceof 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 和 equals,方法是转到 Source -> Generate hashcode() and equals()...
【讨论】:
+1,我将您的代码 sn-p 复制到我的答案中,希望您不要介意。【参考方案3】:你应该实现 hashCode
@Override
public int hashCode()
return id.hashCode();
即使 contains 在没有它的情况下也适用于 ArrayList。您的大问题是您的 equals 需要字符串,而不是 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")));
【讨论】:
使用 HashSets,我的 equals() 方法根本不会在 contains() 检查中被调用,直到我也添加了 hashCode() 方法。以上是关于.Contains() 方法不调用 Overridden equals 方法的主要内容,如果未能解决你的问题,请参考以下文章
list.contains方法既然是调用equ 方法 还用重写 hashcod吗
Groovy集合遍历 ( 调用集合的 every 方法判定集合中的所有元素是否符合闭包规则 | =~ 运算符等价于 contains 函数 | 代码示例 )