无法在Java CopyOnWriteArraySet中删除或查找对象

时间:2011-06-08 13:58:48

标签: 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 == 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

所以,显然对象在集合中。

现在,我想从集合中删除对象:

theSet.remove(theObject);

然后我再次打印该集的内容。 结果:

  

对象1

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

System.out.println(String.valueOf(theSet.contains(theObject)));

结果:

  

显然,该集合找不到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()方法根本没有被调用?

有人可以解释那里发生了什么吗?

我已经尝试比较theObject的hashCodes和集合中的实例,它们都是相等的。

3 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:0)

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);

打印

After add.
[Object 1]

After remove
[]

即使我将hashCode更改为

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

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

答案 2 :(得分:0)

我找到了问题的原因。

我正在使用Hibernate,它创建了一个自己的org.hibernate.collection.PersistentSet实例,它取代了我的CopyOnWriteArraySet!

.contains()和.remove()不起作用的事实是Hibernate中的一个错误:http://opensource.atlassian.com/projects/hibernate/browse/HHH-3799

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

注意:这可能不是所有案例的最佳解决方案。对我来说,它虽然有效。 在上面的链接中,描述了几种解决方法。