How to override equals(), hashCode() & toString() Java methods

Overview

In this blog, we will see how we can override the 3 most common and useful methods of the java Object class. We will see how equals() & hashCode() are related to each other. Besides this, we will see the usefulness of toString().

Methods Class

java.lang.Object

Also read : Why should we override equals() & hashCode()

Override equals()

Let's see how we can override equals() to make it avoid considering the object instances.

Syntax :

public boolean equals(Object o){...}

Code Example :


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));
        System.out.println(b2.equals(b1));
    }
}

class Bank{
    String customerName;
    int accountBalance;

    public Bank(String name , int balance){
        customerName = name;
        accountBalance = balance;
    }

    @Override
    public boolean equals(Object o){
        if(o == this){
            return true;
        }
        if(!(o instanceof Bank)){
            return false;
        }
        Bank bank = (Bank)o;
        return Objects.equals(this.accountBalance,bank.accountBalance) &&
                Objects.equals(this.customerName,bank.customerName);
    }
}

Output :

true
true

In the above code snippet, we have successfully overridden the equals method using the given syntax.

equal() Contract

The equal() method performs the equivalence operation on the non-null object references.

  1. reflexive

    b1.equals(b1); //It should return true
    
  2. symmetric

    b1.equals(b2); //if this is returning true
    b2.equals(b1); //this should also return true
    
  3. transitive

    b1.equals(b2); //if this is returning true
    b2.equals(b3); // and this is also returning true
    b1.equals(b3);  // then this should also return true
    
  4. consistent : It means that the value of equals() changes only if any value of b1 or b2 is changed.

For detailed explanation see : Java Docs

Override hashCode()

The hashCode() returns an integer representing the current instance or object of the class. This value should be consistent with the definition of class equality(if two objects are having same data values then they should be equal to each other irrespective of their instances). Thus, if we are overriding the equals() method, we must have to override hashCode().

Syntax :

public int hashCode() {...}

Simple hashCode() Implementation :

@Override
public int hashCode() {
        return 1; //it will be hard coded and return the same hashcode even for unequal objects, it is not practical.
    }

Improved hashCode() Implementation :

@Override
public int hashCode() {
    return (int) id + name.hashCode() + email.hashCode();
}

IntelliJ IDE's Implementation :

@Override
public int hashCode() {
    return Objects.hash(customerName, accountBalance);
}

hashCode() Contract

  1. During one execution of the Java Application, no matter how many times we call hashCode() on an object it should return the same int value every time. This value may be different during another execution of the application.

    public class codeTest {
     public static void main(String[] args) {
         Bank b1 = new Bank("Harsh",999);
         System.out.println(b1.hashCode());
         System.out.println(b1.hashCode());
         System.out.println(b1.hashCode());
     }
    }
    
    Output :
    -2140575014
    -2140575014 //same
    -2140575014 //same
    
  2. If calling equals() is return true on 2 different objects i.e., when two objects are the same then calling hashCode() on these two objects should return the same value.

    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));
         System.out.println(b1.hashCode());
         System.out.println(b2.hashCode());
     }
    }
    
    Output:
    true
    -2140575014 
    -2140575014 //if true , then b2 value should be the same as b1
    
  3. Two unequal objects may have the same hashCode value. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables.

Additional Notes

Generally, we override either both of them or neither of them. If we are overriding only one of them then it will prevent your class from functioning properly in conjunction with all hash-based collections, including HashMap, HashSet, and Hashtable.

Override toString()

This is a simple yet useful method for getting the string value of an object. String values are more understandable and human-readable than the object's hashcode we can log this value for code debugging purposes.

Syntax:

public String toString() {...}

Default Implementation :

getClass().getName() + '@' + Integer.toHexString(hashCode())

Simple toString() implementation:

@Override
public String toString(){
     return "Name : " + this.customerName + " , Balance : " + this.accountBalance;
    }

Output :

Name : Harsh , Balance : 999

IntelliJ's IDE implmentation:

@Override
public String toString() {
     return "Bank{" +
             "customerName='" + customerName + '\'' +
             ", accountBalance=" + accountBalance +
             '}';
    }

Output :

Bank{customerName='Harsh', accountBalance=999}

Also, read my blog : Violation and fixation of equals() & hashCode()

Conclusion

  • We learned, how to override equals(), hashCode() & toString().

  • Always override hashCode() , if we are overriding equals()

  • We can consider IDE-generated implementation of these methods(preferred choice).