このバグを見つけるのに時間がかかりました...
次の方法を検討してください。
public void foo(Set<Object> set)
{
Object obj=set.iterator().next();
set.remove(obj)
}
空でないハッシュ セットを使用してメソッドを呼び出しましたが、要素は削除されません。
なぜでしょうか?
HashSet の場合、これは、オブジェクトがセットに追加された後にオブジェクトの hashCode が変更された場合に発生する可能性があります。HashSet.remove() メソッドは、間違ったハッシュ バケットを検索し、それを見つけることができない場合があります。
iterator.remove() を実行した場合、これはおそらく発生しませんが、いずれにせよ、 hashCode が変更される可能性のある HashSet にオブジェクトを格納することは、発生するのを待っている事故です(あなたが発見したように)。
パズル?Object.hashCode
、Object.equals
または「ハッシュ セット」が正しく実装されていない場合 (たとえば、「使用java.net.URL
」を参照URI
)。
また、セットに (直接的または間接的に) それ自体が含まれている場合、奇妙なことが起こる可能性があります (正確には、月の実装とフェーズに依存します)。
セットの実装タイプとセット内のオブジェクトは何ですか?
set.put(...)
で一定であることを確認してset.remove(...)
ください。compareTo
メソッドに影響を与える変更がオブジェクトに加えられていないことを確認してください。どちらの場合も、 と の間のコードは、それぞれのクラスの実装によって定義されたコントラクトset.put(...)
にset.remove(...)
違反しています。経験則として、不変オブジェクトをセット コンテンツ (およびマップ キー) として使用することをお勧めします。その性質上、そのようなオブジェクトは、セット内に格納されている間は変更できません。
他のセットの実装を使用している場合は、JavaDoc でそのコントラクトを確認してください。しかし、通常、オブジェクトがセットに含まれている間、equals
または同じままでなければなりません。hashCode
不足している「;」を超えて 後set.remove(obj)
、3 つの状況で発生する可能性があります (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<Object> set)
{
Object obj=set.iterator().next();
iterator.remove();
}
それは次のとおりです。
public void foo(Set<Object> set)
{
Iterator i = set.iterator();
i.next();
i.remove();
}
?
バグは何かに関係している可能性があります:
public void remove()
反復の進行中に、このメソッドを呼び出す以外の方法で基になるコレクションが変更された場合、反復子の動作は規定されていません。
(参考)
問題 (の一部) は、セットが参照ではなく値で渡されることにあると感じずにはいられません。私はJavaの経験があまりないので、完全に間違っている可能性があります。