java.util.Set.remove(Object o) - 问题

rap*_*apt 4 java collections

我必须在这里遗漏一些东西......我有以下代码和输出.你能看出为什么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("-----------------------");

}
Run Code Online (Sandbox Code Playgroud)

输出:

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
-----------------------
Run Code Online (Sandbox Code Playgroud)

PS类别包含:

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

的Javadoc

去掉

boolean remove(Object o)

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

Jon*_*ght 16

你的套装实际上是一套HashSet.类别未实施hashCode.因此,当您去除对象时,对象标识符将用作哈希代码,并且对于每个不同的对象,即使它在语义上等效,它最终也会使用不同的哈希代码,查找错误的位置.哈希集并且没有找到合适的匹配对象.

@Override
public int hashCode() {
    return id.hashCode();
}
Run Code Online (Sandbox Code Playgroud)

Category所有应该很好.

hashCode可以在JavaDoc中读取重写的要求,以获取java.lang.Object#equals:

请注意,通常需要在重写此方法时覆盖hashCode方法,以便维护hashCode方法的常规协定,该方法声明相等对象必须具有相等的哈希代码.

正如本文所暗示的,hashDode的JavaDoc更详细地介绍了这一点.

虽然JavaDoc for remove可能在这个主题上更清晰,但它只引用equals作为规范的一部分,它将删除哪个对象 - 它并不是说它equals是唯一可以使用的东西.

最后,如果你正在使用Eclipse,那么你可以打开一个警告,如果你覆盖equals而没有覆盖hashCode,反之亦然,它会发出警告.