无法在Java';中删除或找到对象;s CopyOnWriteArraySet

无法在Java';中删除或找到对象;s CopyOnWriteArraySet,java,collections,set,Java,Collections,Set,我使用CopyOnWriteArraySet存储自定义类的一个实例,如下所示: public class MyClass{ String _name; public MyClass(String name){ _name = name; } @Override public int hashCode(){ return _name.hashCode(); } @Override public boolean equals(Object obj){ if (obj

我使用CopyOnWriteArraySet存储自定义类的一个实例,如下所示:

public class MyClass{
 String _name;

 public MyClass(String name){
  _name = name;
 }

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

 @Override
 public boolean equals(Object obj){
  if (obj == this) return true;
  if ((obj instanceof MyClass) == false) return false;
  MyClass otherObject = (MyClass) obj;
  return _name.equals(otherObject._name);
 }

 @Override
 public String toString(){
  return _name;
 }
}
当我打印集时,一切似乎都正常:

MyClass theObject = new MyClass("Object 1");
CopyOnWriteArraySet<MyClass> theSet = new CopyOnWriteArraySet();
theSet.add(theObject);

for (MyClass tmp : theSet){
 System.out.println(tmp.toString());
}
然后我再次打印集合的内容。 结果是:

对象1

很奇怪。所以,我试过这个:

System.out.println(String.valueOf(theSet.contains(theObject)));
结果是:

假的

显然,集合无法找到对象,尽管它在那里。 所以,我想,
equals()
方法有问题。 因此,通过在每个函数的第一行添加控制台打印,我更改了
equals()
hashCode()
的方法重写:

 @Override
 public int hashCode(){
  System.out.println("hashCode() called");
  return _name.hashCode();
 }

 @Override
 public boolean equals(Object obj){
  System.out.println("equals() called");
  if (obj == this) return true;
  if ((obj instanceof MyClass) == false) return false;
  MyClass otherObject = (MyClass) obj;
  return _name.equals(otherObject.name);
 }
然后,我再次呼吁:

theSet.remove(theObject);
结果是:

调用hashCode()

因此,根本不调用
equals()
方法

有人能解释一下那里发生了什么事吗


我已经尝试比较对象和集中实例的hashCode,它们都相等。

HashSet使用hashCode,但是CopyOnWriteArraySet不是HashSet(也不是TreeSet),也不调用hashCode()。如果正在调用hashCode,则不使用此集合


这很奇怪,因为我无法重现你的问题

MyClass theObject = new MyClass("Object 1");
CopyOnWriteArrayList<MyClass> theSet = new CopyOnWriteArrayList();
// OR
CopyOnWriteArraySet<MyClass> theSet = new CopyOnWriteArraySet();

theSet.add(theObject);
System.out.println("After add.");
System.out.println(theSet);

theSet.remove(theObject);
System.out.println("\nAfter remove");
System.out.println(theSet);
即使我将哈希代码更改为

public int hashCode() {
    throw new UnsupportedOperationException();
}

它得到相同的结果,因为这些类不使用hashCode()(hashCode()方法除外)

奇怪..我已经测试了您的代码。它在我的环境中运行良好。 并且remove操作不调用hashCode(),而是调用equals()。
我使用的jdk是1.6.0_23。

我找到了问题的原因

我正在使用Hibernate创建自己的org.Hibernate.collection.PersistentSet实例,该实例替换了我的CopyOnWriteArraySet

.contains()和.remove()不起作用是Hibernate中的一个错误:

在我的例子中,解决方案是不重写.hashCode()方法

注意:这可能不是所有情况下的最佳解决方案。但对我来说,它奏效了。
在上面的链接中,介绍了几种解决方法。

问题标题是
CopyOnWriteArraySet
,但代码是
CopyOnWriteArraySet
。你到底在用什么?
remove()
返回什么值-如果为false,列表中不包含该元素。如果您想要一个集合以避免重复项目,请使用
CopyOnWriteArraySet
@Matt Ball抱歉,我的错误。我更正为CopyOnWriteArraySet。remove()返回false。然后集合认为它不包含您试图删除的元素。@Matt Ball是的,我知道,因为我已经发布了:
setSet.contains(theObject)
返回false。问题是:为什么?嗯,我发布的代码只是我真实代码的简化版本,我不能在这里发布,因为它非常复杂和冗长。但是,由于您无法重现该问题,我假设原因一定在我的“复杂”代码中的某个地方。我只是不明白为什么它对我不起作用,为什么不调用equals()。Set如何在不使用equals()的情况下确定内部是否存在对象?@valmar-尝试用一个不太简化的代码版本自己重现问题。如果问题仍然存在,请进一步简化。执行此操作,直到您找到问题所在,或者您有一个足够简单的示例来演示问题,您可以将其发布到此处供其他人尝试。@valmar,HashSet使用hashCode,但是CopyOnWriteArraySet不是HashSet(也不是TreeSet),也不是调用hashCode()。如果正在调用hashCode,则您没有使用此集合。您是对的!我正在使用Hibernate创建自己的org.Hibernate.collection.PersistentSet实例,该实例替换了我的CopyOnWriteArraySet!非常感谢。至少,现在我知道怎么了。如果你将你的评论作为一个真实的答案发表,我会很高兴地将其标记为“正确答案”。我还发现了.remove()和.contains()失败的原因。原因是Hibernate中的一个bug干扰了.hasCode()方法(有关更多信息,请参阅我对这个问题的回答)。
After add.
[Object 1]

After remove
[]
public int hashCode() {
    throw new UnsupportedOperationException();
}