A.I, Data and Software Engineering

WHY DO WE NEED TO OVERRIDE EQUALS AND HASHCODE METHODS IN JAVA/Kotlin

W

In this post, we will discuss why it is important to override equals and hashCode method in Java/Kotlin.

Item 9 in Josh Bloch’s Effective Java suggests always override hashCode() method if the class overrides equals(). In this post, we will discuss why this is necessary and good practice.

 We know that two objects are considered equal only if their references point to the same object and unless we override equals() and hashCode() methods, the class object will not behave properly on hash-based collections like HashMap, HashSet, and Hashtable. This is because hash-based collections are organized like a sequence of buckets. The hash code value of an object is used to determine the bucket where the object would be stored. The same hash code is used again to find the object’s position in the bucket. The key retrieval is basically a two-step process:

  1. Finding the correct bucket using the hashCode() method.
     
  2. Linearly searching the bucket for the key using the equals() method.

Now let’s take an example to demonstrate the need for overriding equals and hashCode method in Java:

class Employee
{
    private String name;
    private int salary;
    public Employee(String name, int salary) {
        this.name = name;
        this.salary = salary;
    }
    @Override
    public String toString() {
        return "{" + name + ", " + salary + "}";
    }
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        if (salary != employee.salary) return false;
        if (name != null ? !name.equals(employee.name) : employee.name != null)
            return false;
        return true;
    }
    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + salary;
        return result;
    }
    // Program to demonstrate the need for overriding equals and hashCode
    // method in Java
    public static void main(String[] args)
    {
        Employee e1 = new Employee("John", 80000);
        Employee e2 = new Employee("John", 80000);
        Set<Employee> employees = new HashSet<>();
        employees.add(e1);
        employees.add(e2);
        System.out.println(employees);
    }
}
Output:
[{John, 80000}]

 
From the output, the set contains only one Employee object even though two different Employee objects are added to it. This is because we have overridden both equals() and hashCode() method in the Employee class. Both objects now point to the same bucket and also holds the same location within the bucket.

 
Now let’s discuss the behaviour of the above program if the equals() method is overridden without overriding hashCode() or vice versa.

1. Override only equals() without overriding hashCode()

Overriding only equals() method without overriding hashCode() causes the two equal instances to have unequal hash codes, that is in violation of 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 objects must produce the same integer result.

 
Since the default hashCode implementation in the Object class return distinct integers for distinct objects, if only equals() method is overridden, e1 will be placed in some bucket and e2 will be placed in some other bucket as e1.hashCode() != e1.hashCode().

So even though both e1 and e2 are equal, they don’t hash to the same bucket. Both of them reside in the collection as separate keys.

It is worth noting that if the class instance is never used in any hash-based collections, then it doesn’t really matter if hashCode() is overridden or not.

2. Override only hashCode() without overriding equals()

If we only override hashCode() method, both e1 and e2 will hash to the same bucket as they produce the same hash code. But since equals() method is not overridden, when the set hashes e2 and iterates through the bucket looking if there is an Employee e such that e2.equals(e) is true, it won’t find any as e2.equals(e1) will be false.

Please note that even though equal objects must have equal hash codes, the reverse is not true. It is perfectly valid to override hashCode() without overriding equals() as objects with equal hash codes need not be equal.

1 comment

💬

A.I, Data and Software Engineering

PetaMinds focuses on developing the coolest topics in data science, A.I, and programming, and make them so digestible for everyone to learn and create amazing applications in a short time.

Categories