尽管 equals 并已实现代码,但删除了 HashSet 上的失败

Remove failing on HashSet despite equals and has code implemented

您好,我正在为一些遗留代码编写集成测试并尝试执行以下操作。 使用两个文档的集合创建交易。保留交易和文件。检索交易并删除其中一份文件。

但是,从 HashSet 中删除失败。等号和散列码方法是在文档 class 上实现的,在下面的代码中,我检查我要删除的文档是否确实与集合中的文档具有相同的散列码并且 'equal' 它。但是删除仍然失败。

我什至调试了 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); 


    } 

    { 

    } 

}

At the time the docs are added to the set they have no Value in their id property which gets added on persist of the deal object as a cascading persist. The id is part of the hash code but as the item I'm trying to delete is retrieved from the database it also has an id.

这说明了一切。

当你向集合中输入一个文档时,存储它的索引取决于输入时的hashCode。你说的是没有id计算的

当您尝试从集合中删除文档时,搜索它的索引取决于您在删除 attempt.nThis 时尝试删除的文档的 hashCode,因为您说了,是用id计算的,所以hashCode不一样

当这两个hashCode不相等时,将找不到要删除的文档。集合中有一个文档与您要删除的文档具有相同的 hashCode(也等于它)并不重要。

进一步说明:

当您将文档添加到集合中时,将存储文档的索引 i 计算如下:

int hash = (key == null) ? 0 : hash(key.hashCode());
int i = indexFor(hash, table.length);

其中 key.hashCode() 是文档的 hashCode。

当您尝试从集合中删除文档时,将以相同的方式计算将搜索该文档的索引 i。如果文档的 hashCode 在此期间发生了变化,则计算出的 i 可能会有所不同,并且不会在实际所在的位置搜索文档,因此不会找到它。

为了解决您的问题,您应该在设置了 id 属性 之后才将文档添加到集合中。如果那不可能,您可以创建一个新的 HashSet,将旧 Set 中的所有文档添加到其中。这将根据更新的 hashCode 值将文档放入 HashSet。