我对某些代码感到有些困惑:
for (AbstractItem item : mSetOfItems) {
if (item.equals(pPrimaryItem))
{
System.out.println("Contains? " + mSetOfItems.contains(pPrimaryItem));
}
}
如何将item.equals(pPrimaryItem)解析为true,并将mSetOfItems.contains(pPrimaryItem)解析为false?因为这就是我在代码中看到的内容。
换句话说,如果我遍历我的集合,我可以找到一个等于我的测试元素的元素。但是如果我使用contains,我的测试元素不会被报告在集合中。我很困惑,因为我认为包含使用的等于。我能俯瞰什么?
答案 0 :(得分:9)
您没有提供mSetOfItems
的类型,但我猜测AbstractItem
会覆盖.equals()
但不会覆盖.hashcode()
。这很糟糕。
如果mSetOfItems
使用哈希码进行查找,它可能基于其类型,您将获得您描述的行为。
您的假设是.contains()
是通过迭代和.equals()
实现的。没有列表界面可以保证。
答案 1 :(得分:6)
mSetOfItems
的实施是什么?
equals()
对于具有不同哈希码的对象返回true,或者对象的hashCode()
自插入到集合中后发生了变化。答案 2 :(得分:3)
如果您的集合是TreeSet
或您使用自定义比较器的其他集合,那么如果比较器被破坏,您可以通过不返回有效的排序顺序或通过具有实际上是相等的比较不平等。当set在内部查找一个元素并使用比较器时,它会做出错误的选择而不会看到该元素。
如果您的集合是HashSet
,则您的散列函数可能会被破坏并导致两个等于具有不同散列码的对象。在内部,HashSet
使用对象的哈希码来确定要查看的位置,最终可能会在错误的桶中查找。
或者,如果您将对象存储在任何类型的Set
中然后修改它们,您最终可能会破坏Set
的内部不变量。例如,如果您将某些内容存储在HashSet
中然后更改其值,那么它将位于错误的存储桶中,如果您有TreeSet
并更改了值,则可能会显示在错误的位置排序顺序。
如果您同时修改集合,则可能您可能已在另一个线程中添加了该元素,但没有任何保证使得该更改的操作在另一个线程中可见。即使添加了元素,第二个线程也不会看到该元素。
答案 3 :(得分:2)
检查班级的hashcode()方法
答案 4 :(得分:2)
如果mSetOfItems
是java.util.HashTable
(或类似的'哈希'收集,设置等),那么您也必须实施hashCode()
。 boolean contains(Object elem)
将首先尝试通过计算其散列并在Collection中检索它来查找传递的对象。一旦包含查找内容,它将使用equals方法根据您的实现验证这两个对象是否是相同的对象。
如果没有正确覆盖,hashCode()
将返回一个不可预测的int
,它通常是对象本身内部地址的整数表示。对于两个不同的对象,无论其实例变量的值如何,这总是不同的。如果没有覆盖,则包含将无法找到任何对象...
实现hashCode()时提醒:
另外,请确保通过尊重其签名正确覆盖了equals函数:
public boolean equals(Object obj);