You are currently viewing How to Override the equals Method Properly in Java

How to Override the equals Method Properly in Java

Introduction

In Java programming, understanding how to override the equals() method is critical for achieving accurate object comparisons. The equals() method is fundamental to many Java operations, including collections and data models. Yet, many developers either overlook or incorrectly implement this essential method. This guide will provide a step-by-step process for overriding equals() correctly, with a focus on best practices and common pitfalls for professional coding.

1. Why Overriding equals() Matters in Java

The equals() method is defined in the Object class, the root of the Java class hierarchy. By default, it checks whether two object references point to the same memory location. However, in practical applications, logical equality—meaning two different objects with the same data—matters more than reference equality.

Failing to override equals() can result in unexpected behavior, especially when using Java collections like HashSet or HashMap.

For example, if you store custom objects in a HashSet without a proper equals() implementation, duplicates may not be detected.

2. The Contract of the equals() Method

When overriding equals(), Java expects you to respect its contract, which specifies:

  • Reflexivity: An object must equal itself.
  • Symmetry: If a.equals(b) is true, then b.equals(a) must also be true.
  • Transitivity: If a.equals(b) and b.equals(c) are true, then a.equals(c) must also be true.
  • Consistency: Multiple invocations should consistently return the same result, provided no fields are changed.
  • Non-nullity: Any object must not equal null.

Violating this contract can lead to bugs that are often difficult to trace. As quoted from the official Java documentation, “It is generally necessary to override the hashCode() method whenever equals() is overridden.” (See Java hashCode best practices for further reading.)

3. Step-by-Step Guide to Overriding equals() in Java

When implementing the equals() method, always follow a structured approach:

  1. Use the @Override annotation: This ensures you are actually overriding a superclass method.
  2. Check for reference equality: If both references point to the same object, return true.
  3. Check for null and type: Return false if the input object is null or not of the correct type.
  4. Cast and compare fields: Compare the relevant fields that determine logical equality.
  5. Follow the contract: Always respect reflexivity, symmetry, transitivity, and consistency.

Here is a practical code snippet illustrating these steps:

@Override
public boolean equals(Object obj) {
    if (this == obj) return true;
    if (obj == null || getClass() != obj.getClass()) return false;
    Person person = (Person) obj;
    return age == person.age && Objects.equals(name, person.name);
}

Before proceeding, ensure you understand the role of the Objects.equals() helper, which safely compares fields (handling null cases).

4. Common Pitfalls When Overriding equals() in Java

Many developers make avoidable mistakes when overriding equals(). Common errors include:

  • Not checking the type of the compared object.
  • Comparing unrelated fields.
  • Forgetting to override hashCode(), leading to collection issues.
  • Using == for reference types instead of .equals().
  • Violating the symmetry or transitivity properties.

The best way to avoid errors is to always test your equals implementation with various scenarios, including self-comparison, comparison with null, and objects of different types.

5. Best Practices and Recommendations

To get the most out of your equals() implementations, always:

  • Use the @Override annotation for compiler checks.
  • Prefer Objects.equals() for null-safe comparisons.
  • Always override hashCode() alongside equals().
  • Document your method, explaining which fields are involved.
  • Test extensively, especially in the context of Java collections.

A well-written equals() method not only helps in application correctness but also increases code maintainability.

6. Complete Example: Overriding equals() in Java

Below is a complete Java class demonstrating proper usage:

package com.kloudly;


import java.util.Objects;

/**
 * Demo class for properly overriding equals() and hashCode() in Java.
 */
public class EqualsDemo {

    public static void main(String[] args){
        Person first = new Person("John Doe", 35);
        Person second = new Person("John Snow", 30);
        boolean isSame = first.equals(second);//false
    }
}

class Person {
    private String name;
    private int age;

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

    /**
     * Properly overrides equals() for logical equality.
     * Checks for reference equality, null, type, and compares significant fields.
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true; // Same object reference
        if (obj == null || getClass() != obj.getClass()) return false; // Null or different type
        Person that = (Person) obj; // Safe cast
        // Compare significant fields
        return age == that.age && Objects.equals(name, that.name);
    }

    /**
     * Always override hashCode() when equals() is overridden.
     * Ensures objects are usable in hash-based collections.
     */
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

This example respects all the guidelines discussed above.

Conclusion

Overriding the equals() method properly in Java is essential for correct object comparison, especially in data models and collections. Remember to respect the method’s contract, avoid common pitfalls, and always override hashCode() as well.

You can find the complete code of this article on GitHub

Noel Kamphoa

Experienced software engineer with expertise in Telecom, Payroll, and Banking. Now Senior Software Engineer at Societe Generale Paris.