Reputation: 4010
I have a HashSet<Obj>
containing one item. A new item trying to be added into the Set is the same as the one existing item, .equals()
. To confirm newElement
is in fact the same, I have some debug prints looping through my HashSet
and printing for each item:
does current item .equals(newElement)
.
This confirms there is a .equals()
object in the set already.
This is where the fun starts, if I call add(newElement)
I am expecting it to not add, or at least overwrite what's already in the set. The set should only have the 1 unique item after the add. In my case, it has 2!
To help figure out why add()
was working that way, I ran a Set.contains(newElement)
which should have returned true, but in my case it returns false. This is why my add()
works the way it does.
Any reason why an item in a set could be .equals(newElement)
but Set.contains(newElement)
could return false? I have checked my .equals()
and it seems to work the way I expect, printing out the objects show what .equals()
is confirming. I thought maybe something with how HashSet
handles add
and contains
but that checks (o==null ? e==null : o.equals(e))
from the Java documentation.
I am also overriding hashCode()
, the values used within I am printing as part of my debug which shows the same logical items.
Upvotes: 0
Views: 869
Reputation: 94
Equals and hashCode methods have a specific contract:
1.If the elements are equal to each other, i.e. equals returns true, then the hashCode value for these objects must match.
2.If the value of hashCode for objects is the same, then this does not mean that equals for them will return true, ie. Objects do not have to be equal to each other, i.e. collisions are possible.
Now consider each case separately:
1.Equals and hashCode are not overridden, this means that equals will return true only if the links are equal, and hashCode can be either equal or not. The size, regardless of the value of hashCode, will be 2.
2.equals and hashCode are redefined, then we will have the same hash value, we will get to the same table cell, equals will determine that the object in the list is already present, accordingly the size will be equal to 1.
3.equals is not re-defined, and hashCode is overridden. In this case, the cell index will be the same, but the same element will not be found in the list and therefore the size will be equal to 2.
4.equals is overridden, and hashCode is undefined. This depends on how the value for hashCode is generated in the Object class. If the values are the same, then the list will be the same, and accordingly, the number of elements in the table will be 1. If different, the search will occur in different lists, and duplicates will not be found, then the size will be equal to 2.
Similarly, the remove, contains operation is performed.
For Example about HashSet/contains:
class Dog{
String color;
public Dog(String s){
color = s;
}
}
public class SetAndHashCode {
public static void main(String[] args) {
HashSet<Dog> dogSet = new HashSet<Dog>();
dogSet.add(new Dog("white"));
dogSet.add(new Dog("white"));
System.out.println("We have " + dogSet.size() + " white dogs!");
if(dogSet.contains(new Dog("white"))){
System.out.println("We have a white dog!");
}else{
System.out.println("No white dog!");
}
}
}
Upvotes: 0
Reputation: 72284
Any reason why an item in a set could be .equals(newElement) but Set.contains(newElement) could return false?
Yes - you need to implement hashCode()
as well as equals, and it needs to check exactly the same fields as equals()
. You say hashcode is only approximately equal, which doesn't make much sense. If hashCode()
returns a different result for two different objects (which it will by default, if you haven't overridden it), then the HashSet
will assume them unique (even if equals()
returns true.)
If hashCode()
returns the same value for both objects, and equals()
return true (symmetrically on both objects), then that will ensure you can't have both objects in the HashSet. There's no (sensible) exceptions to this rule, so if you think both hashCode()
and equals()
are behaving correctly and consistently, there must be a flaw in your logic somewhere.
Upvotes: 3