こんにちは私はいくつかのレガシーコードの統合テストを書いていて、次のことをしようとしています。2つのドキュメントのコレクションで取引を作成します。取引と文書を永続化します。取引を取得し、ドキュメントの1つを削除します。
ただし、HashSetからの削除は失敗します。equalsメソッドとハッシュコードメソッドはドキュメントクラスに実装されており、以下のコードでは、削除しようとしているドキュメントが実際にコレクション内のものと同じハッシュコードを持ち、「等しい」ことを確認します。ただし、削除はまだ失敗します。
HashSetとハッシュマップの実装コードをデバッグしたところ、ハッシュマップの内部で、メソッドreturnEntryForKeyが間違ったindexFor値を見つけているように見えますか?
私は愚かなことをしていますか?
final Entry<K,V> More ...removeEntryForKey(Object key) {
int hash = (key == null) ? 0 : hash(key.hashCode());
int i = indexFor(hash, table.length);
.......。
@Test
public void testDeleteOneOfTwoDocumentsOnlyRemovesOne()
{
Deal originalDeal = new DealBuilder().withProjectName("test-document-project");
Document document1 = new DocumentBuilder().withActive(1).withName("Document One").build();
Document document2 = new DocumentBuilder().withActive(1).withName("Document Two").build();
Set<Document> documents = new MyHashSet<Document>();
originalDeal.setDocuments(documents);
document1.setDeal(originalDeal);
document2.setDeal(originalDeal);
originalDeal.getDocuments().add(document1);
originalDeal.getDocuments().add(document2);
dao.save(originalDeal);
Deal savedDeal = dao.findById(originalDeal.getId());
Set<Document> docs = savedDeal.getDocuments();
assertEquals(2l, docs.size());
long docIdToRemove = 0;
for (Document document : docs)
{
docIdToRemove = document.getId();
break;
}
Document docToRemove = docDao.findById(docIdToRemove);
System.out.println(docToRemove.hashCode());
for (Document document : docs)
{
System.out.println("Hashcode equal? = " + (document.hashCode() == docToRemove.hashCode()));
System.out.println("Objects equal? = " + (document.equals(docToRemove)));
}
boolean contains = docs.contains(docToRemove);
boolean check = docs.remove(docToRemove);
}
{
}
}
ドキュメントがセットに追加された時点では、idプロパティに値がありません。これは、カスケード永続化として取引オブジェクトの永続化時に追加されます。IDはハッシュコードの一部ですが、削除しようとしているアイテムはデータベースから取得されるため、IDもあります。
それがすべてを説明しています。
セットにドキュメントを入力すると、ドキュメントが保存されるインデックスは、入力時のhashCodeによって異なります。あなたが言うように、それはIDなしで計算されます。
セットからドキュメントを削除しようとすると、検索されるインデックスは、削除の試行時に削除しようとしているドキュメントのhashCodeによって異なります。n今回は、おっしゃるように、次のように計算されます。 idなので、hashCodeは異なります。
これらの2つのhashCodeが等しくない場合、削除するドキュメントは見つかりません。削除しようとしているドキュメントと同じhashCodeを持つドキュメントがセットにあるかどうかは関係ありません。これも同じです。
さらなる説明:
セットにドキュメントを追加すると、ドキュメントi
が保存されるインデックスは次のように計算されます。
int hash = (key == null) ? 0 : hash(key.hashCode());
int i = indexFor(hash, table.length);
key.hashCode()
ドキュメントのhashCodeはどこにありますか。
セットからドキュメントを削除しようとすると、i
そのドキュメントが検索されるインデックスが同じ方法で計算されます。その間にドキュメントのhashCodeが変更された場合、計算i
はおそらく異なり、ドキュメントは実際に配置されている場所で検索されないため、見つかりません。
問題を解決するには、idプロパティが設定された後でのみドキュメントをセットに追加する必要があります。それが不可能な場合は、古いセットのすべてのドキュメントを追加する新しいハッシュセットを作成できます。これにより、hashCodeの更新された値に基づいて、ドキュメントがHashSetに配置されます。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加