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

标签 java hashset

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

但是从 HashSet 中删除失败。 equals 和 hash code 方法是在文档类上实现的,在下面的代码中,我检查我尝试删除的文档确实具有与集合中的文档相同的哈希码,并且“等于”它。但是删除仍然失败。

我什至调试了 HashSet 和 HashMap 实现代码,发现在 HashMap 内部,方法 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 的情况下计算的。

当您尝试从集合中删除文档时,搜索该文档的索引取决于您在尝试删除时尝试删除的文档的 hashCode。n这次,正如您所说,它是是根据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,将旧集合中的所有文档添加到其中。这将根据更新后的 hashCode 值将文档放入 HashSet 中。

关于java - 删除 HashSet 上的失败,尽管 equals 并已实现代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28105740/

相关文章:

java - 如何从本地 Java 应用程序中替换 iWay 作为 SAP 适配器

java - (Java) 快速插入、删除和随机选择的数据结构

performance - C# HashSet<T> 搜索性能(与 ObservableCollection<T> 相比)?

java - HashSet<List<T>> 中的唯一条目,其中列表可能包含空条目

java - 根据使用的构建版本选择Gradle属性

java - 想要使用预先签名的 url 将文件上传到 s3 存储桶

java - 获取我的方法调用者的方法名称

java - 如何在 EST 中获取日期

java - 将文件读入列表?

java - 添加到 HashMap 中的哈希集