问题实际上是关于在集合中动态变化的对象。 “包含”方法是每次都单独比较每个对象还是做一些聪明的事情?
如果你在一个集合中有10000个条目,我会期望它更聪明地工作但不确定。或者如果没有,有没有办法通过添加一个钩子来优化它,该钩子会告诉集合对象更新已更改的对象的哈希码?
附加问题:
感谢下面的答案......我还可以问一下ArrayList会发生什么吗?我在文档中找不到任何说明不在ArrayList中放置可变对象的内容。这是否意味着搜索算法只是简单地与每个对象的哈希码进行比较?
答案 0 :(得分:5)
它们对对象进行散列并通过其哈希码查找它。如果它在那里,它将比较对象本身。这是因为具有相同散列的两个或多个对象可能不是同一个对象。
由于Java的哈希集合使用存储桶(链接),因此它们必须查看存储桶中的所有对象。这些对象保存在链接列表中(不是java.util.LinkedList
,而是自定义列表)
这通常非常有效,HashSet.contains()
方法是amortized O(1)(常数时间)。
Java's docs可以回答你问题的第二部分:
注意:如果将可变对象用作set元素,则必须非常小心。 当对象是集合中的元素时,如果对象的值更改,则不会指定集合的行为,影响等于比较的方式。这种禁止的一个特例是,不允许集合将自己作为一个元素包含在内。
答案 1 :(得分:3)
当HashSet
添加到集合中时,contains()
计算元素的hash code。它以一种方式存储它,这使得查找具有相同哈希码的所有元素非常有效。
然后当你调用equals
时,它只需要计算你看的值的哈希码,并找到具有相同哈希码的集合中的所有元素。可能存在多个元素,因为哈希码不是唯一的,但是具有匹配的哈希码的元素可能比该组本身内的元素少得多。然后使用{{1}}检查每个匹配元素,直到找到匹配项或我们的候选人用完为止。
编辑:要回答第二部分,我在第一次读书时错过了,你将无法再找到该元素。你一定不能以任何影响等同的方式更改哈希表中的键或哈希集中的元素,否则你基本上会破坏它。
答案 2 :(得分:1)
简单的答案是 - 不,没有巧妙的事情发生。如果您希望对象的状态以影响其hashCode()
和equals(...)
行为的方式发生变化,那么您不得将其存储在HashSet
中,也不能其他Set
。引用http://download.oracle.com/javase/6/docs/api/java/util/Set.html:
注意:如果将可变对象用作set元素,则必须非常小心。如果在对象是集合中的元素的同时以影响
equals
比较的方式更改对象的值,则不指定集合的行为。这种禁令的一个特例是,不允许集合将自身作为一个要素包含在内。
答案 3 :(得分:0)
HashSet
在引擎盖下使用HashMap
。因此,contains
操作使用对象中的hashCode()
方法来检查它是否存在于HashMap
实现的哈希表中。