有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

集合无法在Java的CopyOnWriteArraySet中删除或找到对象

我使用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());
}

结果是:

Object 1

所以,很明显,对象在集合中

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

theSet.remove(theObject);

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

Object 1

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

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

结果是:

false

显然,集合无法找到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() called

那么,根本不调用equals()方法

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

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


共 (3) 个答案

  1. # 1 楼答案

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

  2. # 2 楼答案

    我找到了问题的原因

    我正在使用Hibernate创建自己的org实例。冬眠收集PersistentSet取代了我的CopyOnWriteArraySet

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

    在我的案例中,解决方案是不覆盖。hashCode()方法

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

  3. # 3 楼答案

    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()方法中),所以它会得到相同的结果