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.
精彩评论