Skip to content

Duplicate elements being added in a set after I change the value after insertion

I have a set with two distinct objects added to it. After insertion, I change one of the objects in such a way that both the objects are equal (as verified by the overridden equals method in object class). At this point in time I have two duplicate elements in a set. Now I try to add these two duplicate objects in a new set and I am still able to add them even though the equals method returns true for them. Below is the code for the same. Can someone please tell me what exactly am I missing?

public class BasicSetImpl{
public int num; String entry;
public BasicSetImpl(int num, String entry){
  this.num = num;
  this.entry = entry;
}

@Override
public int hashCode() {
  return Objects.hash(entry, num);
}

@Override
public boolean equals(Object obj) {
  BasicSetImpl newObj = (BasicSetImpl)obj;
  if (this.num == newObj.num)
    return true;
  else
    return false; 
}



public static void main(String[] args){
  Set<BasicSetImpl> set = new HashSet<>();
  BasicSetImpl k1 = new BasicSetImpl(1, "One");
  BasicSetImpl k2 = new BasicSetImpl(2, "Two");
  set.add(k1);
  set.add(k2);
  
  k2.num = 1;
  
  System.out.println(k1.equals(k2));  //This line returns True
  
  Set<BasicSetImpl> newSet = new HashSet<>();
  newSet.add(k1);
  newSet.add(k2);
  
  //Set.size here is two

Answer

The hash based collection, in this case the HashSet uses the Object hashCode method to calculate the hash value as a function of contents of the object. Since you consider both the entry and num to determine the hashcode value of the object, these two objects has distinct hashcodes since they are different from entry. Thus they belong in two different hash buckets and never be recognized as the same.

However, if you set the entry as follows

k2.entry = "One";

then both k1 and k2 has the same hashcode value. Then they both belong to the same hash bucket and according to the equals method two objects are the same. Therefore, now the duplicates are ignored.

But, there’s a problem lurking here. Ideally, equal objects must have equal hash codes. But, in your case it is not. Two objects are equal if they have the same num value, but they may produce different hashcode values. So the correct solution would be to just change your hashCode as follows.

@Override
public int hashCode() {
    return Integer.hashCode(num);
}

Now, it should behave the way you would expect without the hack we added by setting k2.entry = "One";