According to the JavaDoc of java.util.HashSet.contains() the method does following
Returns true if this set contains the specified element. More formally, returns true if and only if this set contains an element e such that (o==null ? e==null : o.equals(e)).
However this does not seem to work for following code:
public static void main(String[] args) {
HashSet<DemoClass> set = new HashSet<DemoClass>();
DemoClass toInsert = new DemoClass();
toInsert.v1 = "test1";
toInsert.v2 = "test2";
set.add(toInsert);
toInsert.v1 = null;
DemoClass toCheck = new DemoClass();
toCheck.v1 = null;
toCheck.v2 = "test2";
System.out.println(set.contains(toCheck));
System.out.println(toCheck.equals(toInsert));
}
private static class DemoClass {
String v1;
String v2;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((v1 == null) ? 0 : v1.hashCode());
result = prime * result + ((v2 == null) ? 0 : v2.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
DemoClass other = (DemoClass) obj;
if (v1 == null) {
if (other.v1 != null)
return false;
} else if (!v1.equals(other.v1))
return false;
if (v2 == null) {
if (other.v2 != null)
return false;
} else if (!v2.equals(other.v2))
return false;
return true;
}
}
prints out:
false
true
So although the equals
method returns true
, HashSet.contains()
returns false
.
I guess this is because I modified the toInsert instance AFTER it was added to the collection.
However this is in no way documented (or at least I wasn't able to find such). Also the documentation referenced above the equals method should be used but it does not seem so.
When an object is stored in a HashSet
its put in a data structure that's easily (read: efficiently) searchable by the object's hashCode()
. Modifying an object may change its hashCode()
(depending on how you implemented it), but does not update its location in the HashSet
, as the object has no way of knowing its contained in one.
There are a couple of things you can do here:
Modify the implementation of hashCode()
so it isn't affected by the field you're changing. Assuming this field is important to the object's state, and participates in the equals(Object)
method, this is somewhat of a code smell, and should probably be avoided.
Before modifying the object, remove it from the set, and then re-add it once you're done modifying it:
Set<DemoClass> mySet = ...;
DemoClass demo = ...;
boolean wasInSet = mySet.remove(demo);
demo.setV1("new v1");
demo.setV2("new v2");
if (wasInSet) {
set.add(demo);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With