Reason To Override equals() & hashCode()

Overview

In this blog, we will see why we generally override java equals() and hashCode() methods. Besides that, we will see why we should override both of them or neither of them.

Read the blog : How to override equals() & hashCode()

Reason to override equals()

The java.lang.Object class equals() method is used to compare two objects. And this comparison can be done in two ways:

  1. Simple or Naive Comparison : Naive comparison uses the default implementation of equals() which is present in the java.lang.Object class. The default implementation checks whether the two references belong to the same object or not i.e., object1 == object2 i.e., whether the hashCode value is the same or not.
public class Test {
    public static void main(String[] args) {
        Bank b1 = new Bank("Harsh",999);
        Bank b2 = new Bank("Harsh",999);
        System.out.println(b1.equals(b2)); //false : because the hashCodes of objects are having different values
        System.out.println(b1 == b2); //false :  Here we can notice that '==' giving the same result as equals method
    }
}
class Bank{
    String customerName;
    int accountBalance;
    public Bank(String name , int balance){
        customerName = name;
        accountBalance = balance;
    }
}
  1. Hard or Deep Comparison: Deep comparison uses the implementation of equals() which is present in the user-defined class. Users can provide the custom implementation to check whether the data members of two objects are equal or not i.e., object1.data == object2.data.

    public class Test {
     public static void main(String[] args) {
         Bank b1 = new Bank("Harsh", 999);
         Bank b2 = new Bank("Harsh", 999);
         System.out.println(b1.equals(b2)); //true : because this time we are comparing the data fields of class using our custom implementation of equals()
         System.out.println(b1 == b2); //false : Because it is still comparing by checking the reference 
     }
    }
    class Bank {
     String customerName;
     int accountBalance;
    
     public Bank(String name, int balance) {
         customerName = name;
         accountBalance = balance;
     }
    //Custom implementation of equals method
    //overriding the equals method
     @Override
     public boolean equals(Object o) {
         if (o == this) {
             return true;
         }
         if (o==null || o.getClass() != this.getClass()) {
             return false;
         }
         Bank bank = (Bank) o;
         return Objects.equals(this.accountBalance, bank.accountBalance) &&
                 Objects.equals(this.customerName, bank.customerName);
     }
    }
    

    In the above code example, we noticed that we were getting false results even after having the same value of the objects. This raised the need for overriding the equals() in the user-defined class.

Reason to override hashCode()

The hashCode() returns a hash code value for the given object. The default hashCode method defined by java.lang.Object class does return distinct integers for distinct objects. But it may produce the same integer results for unequal objects (as per the 3rd pointer of hashCode contract in Java Docs) which may degrade the performance of hash tables. To improve this, the programmer must provide the custom or IDE-defined implementation for producing distinct integer results for unequal objects. The hashCode() value should be consistent with the definition of equality for the class. Hence, if we are overriding the equals() method, we must have to override hashCode().

Read the blog : How to override equals() & hashCode()

Reason to override both of them

We must have to override both equals() & hashCode() failure to do so will result in the poor functioning of the class when the objects of this class will be used as the key in the Hash-based collection like HashMap, HashSet, etc. Let's look at this problem with an example :

public class codeTest {
    public static void main(String[] args) {
        Bank b1 = new Bank("Harsh", 999);
        Bank b2 = new Bank("Arjun", 999);
        Bank b3 = new Bank("Arjun", 1199);
        Bank b4 = new Bank("Harsh", 999);
        HashMap<Bank,String>  map = new HashMap<>();
        map.put(b1 , "Delhi");
        map.put(b2 , "Mumbai");
        map.put(b3,"Hyderabad");
        System.out.println(map.get(b4));
//Here you would expect the answer should be Delhi, but it would be null.
    }
}
class Bank {
    String customerName;
    int accountBalance;
    public Bank(String name, int balance) {
        customerName = name;
        accountBalance = balance;
    }
    @Override
    public boolean equals(Object o) {
        //some implementation of equals method
    }
}

We would not get the expected result because HashMap will search based on the hashCode value which is different in the case of object b1 and object b2. Hence it will simply give us the null value. Thus, it is suggested that override either both of them or neither of them.

Check out the blog : How HashMap works Internally?

Conclusion

  • Override equals() method for the deep comparison of the objects.

  • hashCode() method should be overridden in order to get the same hashCode for objects having the same data values.

  • If we are overriding equals() , we should also override the hashCode().