ArrayList 的 "Contains" 实现与 HashSet 相比如何?

4

我有一个HashSet<Foo>

我有一个对象,

  1. 等于集合中的一个元素,且
  2. 具有与实现的同一对象相同的哈希码。

但是,如果我调用hashSet.contains(fooInstance),它会返回false

真正奇怪的是,以下行返回true

new ArrayList<Foo>(hashSet).contains(fooInstance)

不幸的是,找到.contains()实现的区别比预期的要困难得多。

但我认为我应该是安全的,因为.equals().hashCode()都可以正常工作。


Foo的hashCode稳定吗? - Mark Rotteveel
@MarkRotteveel 显然不是这样,根据当前的描述,这是导致OP所述行为的唯一原因。 - Thihara
@Thihara 谢谢。那已经很有帮助了。 - fancy
1个回答

9
最有可能的原因是 Foo 的 hashCode 不稳定,而且添加到 HashSet 中的 Foo 实例的 hashCode() 返回值在被添加后发生了改变。理想情况下,你只应该往 HashSet 中添加不可变对象。
出于性能考虑,HashSet 在其条目中存储计算得到的 hashCode,这样它就不需要为每个 get 操作重新计算它。因此,如果对象在 HashSet 内部发生更改,这将不会被察觉,并且你的对象将有效地"丢失"在 HashSet 中。(你仍然可以通过迭代所有元素来获取它,这本质上就是将其复制到一个 ArrayList 中所做的操作)。

这意味着contains使用的是不同于我稍后计算的HashSet吗? 这就解释了为什么我仍然可以在集合中找到一个等于并具有相同哈希码的元素,但仍然不被“包含”。 - fancy
@fancy:不,为什么会这样呢?这只是意味着在您将Foo添加到HashSet时,它的hashCode()返回的值与现在(以及其他对象返回的值)不同。请向我们展示您的FooequalshashCode实现,我们可以告诉您更多信息。 - Joachim Sauer
1
@JoachimSauer 难道 hashcode 也不能识别它所存储的特定哈希桶吗:不同的 hashcode -> 在错误的桶中查找,什么也没找到。 - Mark Rotteveel
@JoachimSauer 抱歉,我拼错了。我是指“不同的哈希码”,而不是 HashSet。这样正确吗? - fancy
@MarkRotteveel:是的,这又是它找不到的另一个原因。 - Joachim Sauer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接