为什么不从套装中删除?

这个bug花了我一段时间才找到……

考虑这种方法:

public void foo(Set set) { Object obj=set.iterator().next(); set.remove(obj) } 

我使用非空哈希集调用该方法,但不会删除任何元素!

那为什么会这样?

对于HashSet,如果对象的hashCode在添加到集合后发生更改,则会发生这种情况。 然后,HashSet.remove()方法可能会查找错误的Hash存储桶而无法找到它。

如果你做了iterator.remove(),这可能不会发生,但无论如何,将对象存储在hashCode可以改变的HashSet中是一个等待发生的事故(如你所发现的)。

难题? 如果Object.hashCodeObject.equals或“哈希集”被错误地实现(例如,请参阅java.net.URL – 使用URI )。

此外,如果集合(直接或间接)包含自身,则可能发生奇怪的事情(确切地说,月亮的实现和阶段依赖于什么)。

集合的实现类型是什么,集合中的对象是什么?

  • 如果它是HashSet,请确保对象的hashCode()方法的值在set.put(...)set.remove(...)之间保持不变。
  • 如果它是TreeSet,请确保不会对影响set的比较器或对象的compareTo方法的对象进行修改。

在这两种情况下, set.put(...)set.remove(...)之间的代码违反了相应类实现定义的协定。 根据经验,最好将不可变对象用作设置内容(以及Map键)。 就其本质而言,这些对象在存储在集合中时无法更改。

如果您正在使用其他一些set实现,请查看其JavaDoc的合同; 但通常要么equals要么hashCode必须保持不变,而对象包含在集合中。

超越失踪的’;’ 在set.remove(obj) ,它可能发生在三种情况下(引自javadoc)。

 ClassCastException - if the type of the specified element is incompatible with this set (optional). NullPointerException - if the specified element is null and this set does not support null elements (optional). UnsupportedOperationException - if the remove method is not supported by this set. 

你也可以尝试:

 public void foo(Set set) { Object obj=set.iterator().next(); iterator.remove(); } 

应该是:

 public void foo(Set set) { Iterator i = set.iterator(); i.next(); i.remove(); } 

该bug可能与以下内容有关:

public void remove()

如果在迭代正在进行中以除调用此方法之外的任何方式修改基础集合,则未指定迭代器的行为。

( 参考 )

我不禁感到(部分)问题是集合是通过值传递的,而不是引用。 我在Java方面没有太多经验,所以我可能完全错了。