尽管等于并且已经实现了代码,但是删除HashSet上的失败

时间:2015-01-23 08:24:43

标签: java hashset

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

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

我甚至通过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); 


    } 

    { 

    } 

}

1 个答案:

答案 0 :(得分:2)

  

当文档被添加到集合中时,它们的id属性中没有Value,它会在交易对象的持久性中添加为级联持久性。 id是哈希码的一部分,但是当我尝试删除的项目从数据库中检索时,它也有一个id。

这解释了一切。

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

当您尝试从集合中删除文档时,搜索它的索引取决于您在删除尝试时尝试删除的文档的hashCode。那么,正如您所说,它是用id计算,所以hashCode是不同的。

当这两个hashCodes不相等时,将无法找到要删除的文档。在集合中使用与您尝试删除的doc相同的hashCode并且它也等于它的文档并不重要。

进一步说明:

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

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

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

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

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