我在Java中有一个ArrayList,它由一个包含两个字符串和一个整数的类型组成。我可以成功测试此ArrayList的一个元素是否等于另一个,但我发现contains方法失败。我相信这是因为我的类型不是原始的。
现在我看到两个替代方案,我想知道哪个是最好的选择:
通过迭代ArrayList并测试每个元素与我正在寻找的元素的相等性然后打破循环来实现我自己的contains方法。
或者使用我的类型的HashMap作为键,使用整数作为值而不是ArrayList。在这里,我可以使用方法containsKey来检查HashMap中是否已经存在一个元素。
对#2进行处理的唯一警告是,在我的情况下,该值很大程度上是多余的。
答案 0 :(得分:23)
很有可能,您只是忘记在您的类型中覆盖equals()
和hashCode()
。 equals()
是contains()
检查的内容。
来自Javadoc:
如果此列表包含指定的元素,则返回
true
。更正式的是,当且仅当此列表包含至少一个true
元素e
时,才返回(o==null ? e==null : o.equals(e))
。
由于equals
的默认实现测试引用相等性,因此它不适合像这样的自定义数据类型。
(如果你没有覆盖equals
和hashCode
,那么在HashMap
中使用类型作为键也同样徒劳无功。)
修改:请注意,要覆盖,您必须提供完全签名。
class MyDataType {
public boolean equals(MyDataType other) { // WRONG!
...
}
public boolean equals(Object other) { // Right!
...
}
}
这是使用@Override
注释的一个非常有力的论据;如果使用@Override
注释,第一个示例在编译时将失败。
答案 1 :(得分:14)
我的猜测是你只编写了一个“强类型”equals方法而不是覆盖equals(Object)。换句话说,如果你有:
public boolean equals(Foo f)
你需要
public boolean equals(Object o)
也可以覆盖Object.equals。
这适合“equals工作,但包含不适用,因为你的测试可能会调用强类型的等号,但ArrayList不会。”/ p>
答案 2 :(得分:3)
你是否覆盖了equals方法?这是使包含正常工作所必需的。
答案 3 :(得分:2)
请记住,如果不覆盖equals()方法,那么如果类型的两个对象是该对象的相同实例,则它们只相等。 ArrayList类使用此方法检查它是否包含给定对象。此外,您需要准确匹配签名,这意味着它必须将Object作为参数而不是Foo。
此外,Object契约规定,只要覆盖equals(),就必须覆盖hashCode()。如果不这样做,那么HashMap或HashSet将不会将您的两个对象标识为相等,即使ArrayList执行此操作(HashMap检查相同的哈希值,然后对它们调用equals()以检查实际相等性)。因此,如果ArrayList表示两个项不相等,那么HashMap也无法做到。这意味着您的第二个解决方案不起作用。
我的建议是检查你是否实际上正确地覆盖了equals()和hashCode(),并且它们的签名与Object类中的签名匹配。
答案 4 :(得分:0)
可能会使用Integer类吗?然后你可以做对象比较