Always override hashcode when you override equals

This is a piece of advice from Joshua Bloch on Effective Java book.

You must override hashCode() in every class that overrides equals(). Failure to do so will result in a violation of the general contract for Object.hashCode(), which will prevent your class from functioning properly in conjunction with all hash-based collections, including HashMap, HashSet, and Hashtable.

Explanation with code:

Hash-based collections, such as HashMap, HashSet, and Hashtable use a hashcode value of an object to determine how it should be stored inside a collection. The hashcode is used in order to locate the object in its collection.

Retrieval from hash-based collections is a two-step process:

  • Find the right bucket (using hashCode())
  • Search the bucket for the right element (using equals() )

Lets check why we should overrride hashcode() when we override equals().

Consider a User class that has two fields: age and name.

public class User {

    String name;
    int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == this)
            return true;
        if (!(obj instanceof User))
            return false;
        User user = (User) obj;
        return user.getAge() == this.getAge()
                && user.getName() == this.getName();
    }
 
    @Override
    public int hashCode() {
            int result=17;
            result=31*result+age;
            result=31*result+(name!=null ? name.hashCode():0);
            return result;
    }
   
}

Now write a test class to check the above class

public class UserTest {
    public static void main(String[] args) {
        User firstUser = new User("Joe", 35);
        User secondUser = new User("Joe", 35);

        HashSet users = new HashSet();
        users.add(firstUser);
        System.out.println(users.contains(secondUser));
        System.out.println("firstUser.hashCode():  " + firstUser.hashCode()
        + "  secondUser.hashCode():" + secondUser.hashCode());
    }
}
// Output
true
firstUser.hashCode():  64563636  secondUser.hashCode(): 64563636

But if we comment out the hascode override then it will produce the following result:

// Output
flase
firstUser.hashCode():  64563636  secondUser.hashCode(): 72562565