When I run this code why only hashCode()
is called not equals
method while my hashCode()
implementation generate same hashCode
for both entries to HashSet
?
import java.util.HashSet; public class Test1 { public static void main(String[] args) { Student st=new Student(89); HashSet st1=new HashSet(); st1.add(st); st1.add(st); System.out.println("Ho size="+st1.size()); } } class Student{ private int name; private int ID; public Student(int iD) { super(); this.ID = iD; } @Override public int hashCode() { System.out.println("Hello-hashcode"); return ID; } @Override public boolean equals(Object obj) { System.out.println("Hello-equals"); if(obj instanceof Student){ if(this.ID==((Student)obj).ID){ return true; } else{ return false; } } return false; } }
The output for this is:
Hello-hashcode Hello-hashcode Ho size=1
Overriding only equals() method without overriding hashCode() causes the two equal instances to have unequal hash codes, which violates the hashCode contract (mentioned in Javadoc) that clearly says, if two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two ...
In order to use our own class objects as keys in collections like HashMap, Hashtable etc.. , we should override both methods ( hashCode() and equals() ) by having an awareness on internal working of collection. Otherwise, it leads to wrong results which we are not expected.
In HashMap, hashCode() is used to calculate the bucket and therefore calculate the index. equals() method: This method is used to check whether 2 objects are equal or not. This method is provided by the Object class. You can override this in your class to provide your implementation.
The hash set checks reference equality first, and if that passes, it skips the .equals
call. This is an optimization and works because the contract of equals
specifies that if a == b
then a.equals(b)
.
I attached the source code below, with this check highlighted.
If you instead add two equal elements that are not the same reference, you get the effect you were expecting:
HashSet st1=new HashSet(); st1.add(new Student(89)); st1.add(new Student(89)); System.out.println("Ho size="+st1.size());
results in
$ java Test1 Hello-hashcode Hello-hashcode Hello-equals Ho size=1
Here's the source code from OpenJDK 7, with equality optimization indicated (from HashMap, the underlying implementation of HashSet):
public V put(K key, V value) { if (key == null) return putForNullKey(value); int hash = hash(key.hashCode()); int i = indexFor(hash, table.length); for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; // v-- HERE if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(hash, key, value, i); return null; }
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