开发者

Cannot remove or find an object in Java's CopyOnWriteArraySet

I use CopyOnWriteArraySet to store one instance of a custom class, which looks like this:

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

When I print the set, everything seems ok:

MyClass theObject = new MyClass("Object 1");
CopyOnWriteArraySet<MyClass> theSet = new CopyOnWriteArraySet();
theS开发者_StackOverflow中文版et.add(theObject);

for (MyClass tmp : theSet){
 System.out.println(tmp.toString());
}

The result is:

Object 1

So, obviously the object is in the set.

Now, I want to remove the object from the set:

theSet.remove(theObject);

Then I print the content of the set again. The result:

Object 1

Very weird. So, I tried this:

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

The result:

false

Obviously, the set cannot find theObject although it's there. So, I thought, there's something wrong with the equals() method. Thus, I changed the method overrides of equals() and hashCode() by adding a console print to the first line of each function:

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

Then, I call again:

theSet.remove(theObject);

The result:

hashCode() called

So, the equals() method isn't called at all?

Can someone explain what's going on there?

I already tried to compare the hashCodes of theObject and the instance inside the set and they're both equal.


Strange..i have tested your codes. And it works well in my environment. And the remove operation doesn't call hashCode() but call equals() instead. The jdk what i used is 1.6.0_23.


HashSet's use the hashCode, however the CopyOnWriteArraySet is not a HashSet (neither is TreeSet) and neither call hashCode(). If hashCode is being called you are not using this collection.


It is very weird because I cannot reproduce your problem.

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

prints

After add.
[Object 1]

After remove
[]

Even when I change hashCode to

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

it gets the same result because these classes don't use hashCode() (except in the hashCode() method)


I found the reason for the problem.

I'm using Hibernate which creates an own instance of org.hibernate.collection.PersistentSet which replaced my CopyOnWriteArraySet!

The fact that .contains() and .remove() didn't work was a bug in Hibernate: http://opensource.atlassian.com/projects/hibernate/browse/HHH-3799

The solution in my case was to not override the .hashCode() method.

Note: This might not be the best solution for all cases. For me, it worked though. In the link above, there are several workarounds described.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜