5

这个bug花了我一段时间才找到...

考虑这种方法:

public void foo(Set<Object> set)
{
    Object obj=set.iterator().next();
    set.remove(obj)
}

我使用非空哈希集调用该方法,但不会删除任何元素!

为什么会这样?

4

7 回答 7

9

对于 HashSet,如果对象的 hashCode 在添加到集合后发生更改,则会发生这种情况。然后 HashSet.remove() 方法可能会在错误的 Hash 桶中查找并找不到它。

如果您执行了 iterator.remove() ,这可能不会发生,但无论如何,将对象存储在其 hashCode 可以更改的 HashSet 中是等待发生的意外(正如您所发现的那样)。

于 2009-07-06T12:13:49.483 回答
3

谜?如果Object.hashCode,Object.equals或“散列集”实施不正确(例如,请参见java.net.URL- 使用URI)。

此外,如果集合(直接或间接)包含自身,则可能会发生一些奇怪的事情(确切地说是什么是实现和月相依赖)。

于 2009-07-06T12:00:22.720 回答
2

集合的实现类型是什么,集合内有哪些对象?

  • 如果是 HashSet,请确保对象的 hashCode() 方法的值在set.put(...)和之间保持不变set.remove(...)
  • 如果它是 TreeSet,请确保没有对影响集合比较器或对象compareTo方法的对象进行修改。

在这两种情况下,代码之间的代码都set.put(...)违反set.remove(...)了各自类实现定义的契约。根据经验,使用不可变对象作为设置内容(和 Map 键)是一个好主意。就其本质而言,此类对象在存储在集合中时无法更改。

如果您正在使用其他集合实现,请查看其 JavaDoc 以获取其合同;但当对象包含在集合中时,通常要么equals保持hashCode不变,要么保持不变。

于 2009-07-06T12:06:24.063 回答
1

除了缺少的';' 之后set.remove(obj),它可能在三种情况下发生(引自 javadoc)。

ClassCastException - if the type of the specified element is incompatible with this set (optional).
NullPointerException - if the specified element is null and this set does not support null elements (optional). 
UnsupportedOperationException - if the remove method is not supported by this set.

你也可以试试:

public void foo(Set<Object> set)
{
    Object obj=set.iterator().next();
    iterator.remove();
}
于 2009-07-06T12:01:28.303 回答
1

应该是:

public void foo(Set<Object> set)
{
    Iterator i = set.iterator();
    i.next();
    i.remove();
}

?

该错误可能与以下内容有关:

公共无效删除()

如果在迭代过程中以除调用此方法之外的任何方式修改了底层集合,则迭代器的行为是未指定的。

参考

于 2009-07-06T12:05:01.803 回答
0

我的类似案例:

在此处输入图像描述

这对我不起作用。我的班级组需要@Override equalshashCode,如下所示:

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((id == null) ? 0 : id.hashCode());
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj) return true;
    if (obj == null) return false;
    if (getClass() != obj.getClass()) return false;
    Group other = (Group) obj;
    if (id == null) {
        if (other.id != null) return false;
    } else if (!id.equals(other.id)) return false;
    return true;
}

这迫使通过id字段比较 POJO,没有月相。

于 2021-12-22T12:31:41.940 回答
-3

我不禁觉得(部分)问题是集合是按值传递的,而不是引用传递。不过,我在 Java 方面没有太多经验,所以我可能完全错了。

于 2009-07-06T12:15:42.760 回答