Java equals() and hashCode()

Difference between comparison and equality check

In many cases we have to compare objects. There are different type of comparison. In some cases you need to order (sort) some object based on some rules. Then in Java you can use Comparable and Comparator. In other cases we need to check if the object are logically equal for the application. This is done by overriding equals and hashcode methods which are part of the Object class.

Rules when implement equals and hashCode

When we implement equals method we have to comply with this rules which can be see in the documentation:

  • The equals method implements an equivalence relation on non-null object references
  • It is reflexive: for any non-null reference value x, x.equals(x) should return true.
  • It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
  • It is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true.
  • It is consistent: for any non-null reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, provided no information used in equals comparisons on the objects is modified.
  • For any non-null reference value x, x.equals(null) should return false.

As general rule if we implement equals we also need to implement hashCode method which has own rules:

  • Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
  • If two objects are equal according to the equals method, then calling the hashCode method on each of the two objects must produce the same integer result.
  • It is not required that if two objects are unequal according to the equals method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables.

hashCode is used for performance reasons in some Java Collections and Maps like HashSet, HashMap.

IDE generation of equals and hashCode

Also in many cases our IDE can help us a lot generating for us the equals and hashCode method based on the class properties. Still we have to be careful what mean equals in the application sense. Sometimes it might not include all fields or sometimes frameworks or libraries like Hibernate can have different requirements for equals and hashCode from our default generated implementations.

Example of equals and hashCode

Lets see example of implementation of equals and hashCode. We need to create two files Person.java in which equals and hashCode will be implemented and another file MainEqualsHashcode.java where several objects from class Person will be tested:

import java.util.Objects;

public class Person {
    private String name;
    private Integer age;

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

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

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}
public class MainEqualsHashcode {
    public static void main(String[] args) {
        Person a = new Person("Harry", 25);
        Person b = new Person("Harry", 25);
        Person c = new Person("Ron", 26);

        // Here is true because person Harry == Harry
        if(a.equals(b))
        {
            System.out.println("Person 'a' and 'b' are the same");
        }

        // Here is false because person Harry != Ron
        if(a.equals(c))
        {
            System.out.println("This message should not be visible");
        }

        // also show Person hashcode
        System.out.println("Person 'a' hashCode: " + a.hashCode());
        System.out.println("Person 'b' hashCode: " + b.hashCode());
        System.out.println("Person 'c' hashCode: " + c.hashCode());
    }
}

Output:

Person 'a' and 'b' are the same
Person 'a' hashCode: -2140576422
Person 'b' hashCode: -2140576422
Person 'c' hashCode: 2553930

Operator ‘==’ what is and what is not in Java

Important! Now in other programming languages usually it is used “==” operator but in Java this operator only check if the objects point to the same element in the memory. It will compare their addresses if they are the same:

public class MainWrongEqualsCheck {
    static class Person {
        private String name;
        private Integer age;

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

    public static void main(String[] args) {
        Person a = new Person("Agata", 20);
        Person b = new Person("Agata", 20);

        if(a == b)
        {
            System.out.println("They are equal.");
        }
        else {
            System.out.println("Never check object equality with ==");
            // In Person, we didn't override toString() from Object
            // Default implementation toString():
            // getClass().getName() + '@' + Integer.toHexString(hashCode())
            // where default implementation of hashCode() will return
            // address of the object. Now we can see that there is difference
            // in the addresses of the objects, although they are from
            // the same class
            System.out.println(a);
            System.out.println(b);
        }
    }
}

Output:

Never check object equality with ==
MainEqualsAndHashcode$Person@5acf9800
MainEqualsAndHashcode$Person@4617c264

Where we can use operator ‘==’

Now there is several exceptions for this rule:

  • In JVM the primitive types directly contain value (not address) to work faster and this mean that “==” actually will check if they have the same value. Also for the primitive types (int, float, boolean, double) we do not have methods so there is no equals method thus the only two options is to use “==” operator to check equality for primitive types or we have to wrap (for int we have Integer, for boolean we have Boolean and so on) them with Wrapper classes and then in this wrapper classes we will have access to the equals method.
  • If we compare static Classes and Enums they reside in the static part of the memory in Java. There they have only one instance (Singleton) so using “==” operator is possible to be used instead of equals because we are sure that the memory address it will point only to one possible place.

Example of program that uses “==” operator in comparison for primitive types and static memory objects:

public class MainPrimitiveTypeEquality {
    static class MyClass {
        private Integer k;
    }

    enum MyEnum
    {
        VALUE_A,
        VALUE_B
    }

    public static void main(String[] args) {
        int a = 500;
        int b = 500;

        if(a == b)
        {
            System.out.println("Primitive type variables 'a' and 'b' are equal");
        }

        Integer wrapperA = Integer.valueOf(a);
        Integer wrapperB = Integer.valueOf(b);

        if(wrapperA.equals(wrapperB))
        {
            System.out.println("Also wrapper Integer variables are equal");
        }

        if(MyEnum.VALUE_B == MyEnum.VALUE_B)
        {
            System.out.println("enums are in static memory as singletons");
        }

        if(MyClass.class == MyClass.class)
        {
            System.out.println("MyClass are in static memory as singleton");
        }
    }
}
Primitive type variables 'a' and 'b' are equal
Also wrapper Integer variables are equal
enums are in static memory as singletons
MyClass are in static memory as singleton

Leave a Comment

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

The reCAPTCHA verification period has expired. Please reload the page.