包含和等于

时间:2011-08-26 00:44:07

标签: java data-structures

我对某些代码感到有些困惑:

for (AbstractItem item : mSetOfItems) {
        if (item.equals(pPrimaryItem))
        {
            System.out.println("Contains? " + mSetOfItems.contains(pPrimaryItem));
        }
}

如何将item.equals(pPrimaryItem)解析为true,并将mSetOfItems.contains(pPrimaryItem)解析为false?因为这就是我在代码中看到的内容。

换句话说,如果我遍历我的集合,我可以找到一个等于我的测试元素的元素。但是如果我使用contains,我的测试元素不会被报告在集合中。我很困惑,因为我认为包含使用的等于。我能俯瞰什么?

5 个答案:

答案 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)

如果mSetOfItemsjava.util.HashTable(或类似的'哈希'收集,设置等),那么您也必须实施hashCode()boolean contains(Object elem)将首先尝试通过计算其散列并在Collection中检索它来查找传递的对象。一旦包含查找内容,它将使用equals方法根据您的实现验证这两个对象是否是相同的对象。

如果没有正确覆盖,hashCode()将返回一个不可预测的int,它通常是对象本身内部地址的整数表示。对于两个不同的对象,无论其实例变量的值如何,这总是不同的。如果没有覆盖,则包含将无法找到任何对象...

实现hashCode()时提醒:

  • 每当在执行Java应用程序期间多次在同一对象上调用它时,hashCode方法必须始终返回相同的整数,前提是不修改对象的equals比较中使用的信息。从应用程序的一次执行到同一应用程序的另一次执行,此整数不需要保持一致。
  • 如果两个对象根据equals(Object)方法相等,则对两个对象中的每一个调用hashCode方法必须生成相同的整数结果。
  • 如果两个对象根据equals(java.lang.Object)方法不相等,则不需要在两个对象中的每一个上调用hashCode方法必须生成不同的整数结果。但是,程序员应该知道为不等对象生成不同的整数结果可能会提高哈希表的性能。

另外,请确保通过尊重其签名正确覆盖了equals函数:

 public boolean equals(Object obj);