【问题标题】:java.util.Set.remove(Object o) - problemjava.util.Set.remove(Object o) - 问题
【发布时间】:2011-09-07 22:50:59
【问题描述】:

我必须在这里遗漏一些东西......我有以下代码和输出。你能明白为什么Category categoryToBeDeleted 没有从result 中每本书的类别集中删除吗?

谢谢!!

代码:

List<Book> result = ... //get list from database

final Category categoryToBeDeleted = ... //get category from database

System.out.println("categoryToBeDeleted id: " + categoryToBeDeleted.getId() + " name: " + categoryToBeDeleted.getName());

for (Book book : result) {
    System.out.println("before remove :");
    for (Category category : book.getCategories()) {
        System.out.println("category id: " + category.getId() + " name: " + category.getName() + " equals: " + category.equals(categoryToBeDeleted));
    }
    System.out.println("-----------------------");

    book.getCategories().remove(categoryToBeDeleted);

    System.out.println("after remove :");
    for (Category category : book.getCategories()) {
        System.out.println("category id: " + category.getId() + " name: " + category.getName() + " equals: " + category.equals(categoryToBeDeleted));
    }
    System.out.println("-----------------------");

}

输出:

categoryToBeDeleted id: 10 name: cosmetics
before remove :
category id: 10 name: cosmetics equals: true
category id: 1 name: cleaning equals: false
-----------------------
after remove :
category id: 10 name: cosmetics equals: true
category id: 1 name: cleaning equals: false
-----------------------
before remove :
category id: 9 name: junk-2 equals: false
category id: 10 name: cosmetics equals: true
-----------------------
after remove :
category id: 9 name: junk-2 equals: false
category id: 10 name: cosmetics equals: true
-----------------------
before remove :
category id: 6 name: knick-knacks equals: false
category id: 4 name: baby equals: false
category id: 9 name: junk-2 equals: false
category id: 10 name: cosmetics equals: true
-----------------------
after remove :
category id: 6 name: knick-knacks equals: false
category id: 4 name: baby equals: false
category id: 9 name: junk-2 equals: false
category id: 10 name: cosmetics equals: true
-----------------------

附:类别包含:

@Override
public boolean equals(Object obj) {
    if (obj instanceof Category) {
        Category thatCategory = (Category) obj;
        return this.id.equals(thatCategory.id);
    }
    return false;
}

Javadoc

remove

布尔删除(对象o)

如果存在,则从该集合中删除指定元素(可选操作)。更正式地说,如果这个集合包含这样一个元素,则删除一个元素 e 使得 (o==null ? e==null : o.equals(e))。如果此 set 包含该元素(或等效地,如果此 set 由于调用而更改),则返回 true。 (一旦调用返回,此集合将不包含该元素。)

【问题讨论】:

    标签: java collections


    【解决方案1】:

    你的集合实际上是一个HashSet。类别未实施hashCode。结果,当你去删除对象时,对象标识符被用作哈希码,并且对于每个不同的对象,即使它在语义上是等效的,它最终也会使用不同的哈希码,在错误的地方查找哈希集并没有找到合适的匹配对象。

    添加

    @Override
    public int hashCode() {
        return id.hashCode();
    }
    

    Category,一切都会好起来的。

    覆盖hashCode的要求可以在JavaDoc for java.lang.Object#equals中读取:

    注意,一般需要重写hashCode方法 每当此方法被覆盖时,以保持一般 hashCode 方法的契约,它规定相等的对象必须 具有相同的哈希码。

    正如本文所暗示的,JavaDoc for hashCode 对此进行了更详细的介绍。

    虽然remove 的JavaDoc 在这个主题上可能更清楚,但它只引用equals 作为规范的一部分,它将删除哪个对象——它并没有说equals 是它唯一的东西会用。

    最后,如果您使用的是 Eclipse,您可以打开一个警告,如果您覆盖 equals 而不覆盖 hashCode,则会发出警告,反之亦然。

    【讨论】:

    • 谢谢!首先,您的解决方案有效。现在,我在帖子底部添加了 Set.remove(Object o) 的 javadoc.... 我如何从那里获得覆盖 hashcode() 的要求?它只是说该方法使用 equals()。
    • 我已经添加了一些更多的细节。
    • 谢谢!这是非常有用的。并感谢 Eclipse 提示。
    【解决方案2】:

    如果你重写equals(),你也应该重写hashCode()。

    【讨论】:

      猜你喜欢
      • 2013-01-16
      • 1970-01-01
      • 2020-09-23
      • 2014-09-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多