Overriding equals() method in Java

0
6390

Comparing is something that you would do a lot in programming. It’s easy in Java to compare primitive variable using double equals sign “==”. However, it requires a little bit of work when you want to compare the reference variable or objects to objects.

In this particular article, let’s see how we should override the equals() method in Class, therefore we’ll be able to compare two objects that initiated from the same class.

Where does the equals() method come from?

Whenever you create a brand new class even you don’t define the equals() method inside that class, the object that initiated from the class still can call the equals() method.

package com.samderlust;

public class Patient {
    private String firstName;
    private String lastName;
    private int healthCardNumber;

    public Patient(){
        this("unknown", "unknown", -1);
    }

    public Patient(String firstName, String lastName, int healthCardNumber) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.healthCardNumber = healthCardNumber;
    }

    public static void main(String[] args) {
        Patient p1 = new Patient();
        p1.equals(p1);
    }
}
// true

The equals() method here doesn’t come from magic. It is inherited from the class Object. In Java, the Object class is the “God Father of all classes”. It means, all the classes you create in your program are children, grandchildren,… of this Object Class. In other words, every class that you create can have access to the equals() method.

“Class Object is the root of the class hierarchy. Every class has Object as a superclass. All objects, including arrays, implement the methods of this class.” – Oracle

How does the equals() method work?

The snippet above gives us a class of Patient with 3 attributes: firstName, lastName, and healthCardNumber. What we expect when compare 2 instances p1 and p2 are it will compare each attribute to make sure these 2 objects are similar. It’s easy to tell that the output of  p1.equals(p1) is true as p1 and p1 is the exact same thing. But let’s see the example below:

public static void main(String[] args) {
    Patient p1 = new Patient();
    Patient p2 = new Patient();
    Patient p3 = new Patient("Michel", "Jaction", 123);

    System.out.println(p1.equals(p1));
    System.out.println(p1.equals(p2));
    System.out.println(p1.equals(p3));
}
//output
true
false
false

Oops, what happened? Why p1.equals(p2) return false while they have the same values in 3 attributes? You may have the same question, right?

“The equals method for class Object implements the most discriminating possible equivalence relation on objects; that is, for any non-null reference values x and y, this method returns true if and only if x and y refer to the same object (x == y has the value true).” — Oracle

We can have the same output with the code below:

System.out.println(p1 == p1); // true
System.out.println(p1 == p2); // false
System.out.println(p1 == p3); // false
// This is the equals method in Object class.
public boolean equals(Object obj) {
        return (this == obj);
}

Obviously, the original equals() just return true if 2 objects have the same values and memory location. That’s why the only true comparison is the first one.  Let’s override the equals() method in Patient class so that we can get the result that we expect.

Overriding equals() method in a class.

1.Checking if any object we pass in this method is null or not if null return null and don’t care about the rest of the code.

Whenever the method hit return keyword, it returns and stops executing.

2. Checking if the object that we pass in is an instance of Patient class (respectively for other class). If it not, return false.

3. Creating a new object from Patient class, and assign it to the object obj that we pass in the method. Since we pass in an object with the datatype of Object, we should cast it into the specific datatype/object type we want to compare, in this case, (Patient). Therefore, it can access the attributes of the Patient class.

4. Comparing each field of the current object with the one we pass into. It returns a boolean value: true if all the comparisons are true, false if any is false

After overriding equals method, we get the result as below:

System.out.println(p1.equals(p1)); // true
System.out.println(p1.equals(p2)); // true
System.out.println(p1.equals(p3)); // false

How this.firstName.equals(patient.firstName) work inside the override equals() method?

Thanks to Polymorphism, the same method can execute in different ways depends on the situation. Read more about polymorphism here.

Overriding equals() method in a subclass.

This time, we create a new subclass of Patient and also override the equals() method.

public class OutPatient extends Patient {
    private double distanceFromClinic;
    private boolean mobility;

    public OutPatient(String firstName, String lastName, int healthCardNumber,
                      double distanceFromClinic, boolean mobility) {
        super(firstName, lastName, healthCardNumber);
        this.distanceFromClinic = distanceFromClinic;
        this.mobility = mobility;
    }

      @Override
    public boolean equals(Object o) {
        if (this == o) return true;//1
        if (o == null || getClass() != o.getClass()) return false;//2
        if (!super.equals(o)) return false;//3
        OutPatient that = (OutPatient) o;//4
        //5
        return Double.compare(that.distanceFromClinic, distanceFromClinic) == 0 &&
                mobility == that.mobility;
    }

    @Override
    public int hashCode() {

        return Objects.hash(distanceFromClinic, mobility);
    }
}

It’s almost the same with what we write in the superclass. The thing to notice here is line 3

if  (!super.equals(obj)) return false;

We need to check if the  2 objects we want to compare have similar 3 attributes in term of the superclass (firstName, lastName, and healthCardNumber) since they’re declared there.

Only after then, we go on to check the 2 attributes: istanceFromClinic and mobility that are declared in the OutPatient subclass.

Click to see the source code

public class Patient {
    private String firstName;
    private String lastName;
    private int healthCardNumber;

    public Patient(){
        this("unknown", "unknown", -1);
    }

    public Patient(String firstName, String lastName, int healthCardNumber) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.healthCardNumber = healthCardNumber;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true; //1
        if (o == null || getClass() != o.getClass()) return false; //2
        Patient patient = (Patient) o;//3
        //4
        return healthCardNumber == patient.healthCardNumber &&
                Objects.equals(firstName, patient.firstName) &&
                Objects.equals(lastName, patient.lastName);
    }

    @Override
    public int hashCode() {

        return Objects.hash(firstName, lastName, healthCardNumber);
    }

    public static void main(String[] args) {
        Patient p1 = new Patient();
        Patient p2 = new OutPatient();
        Patient p3 = new Patient("Michel", "Jaction", 123);


        System.out.println(p1.equals(p1));
        System.out.println(p2.equals(p2));
        System.out.println(p1.equals(p3));

        System.out.println(p1 == p1);
        System.out.println(p1 == p2);
        System.out.println(p1 == p3);
    }
}

import java.util.Objects;

public class OutPatient extends Patient {
    private double distanceFromClinic;
    private boolean mobility;

    public OutPatient() {
        super();
        this.distanceFromClinic = 10;
        this.mobility = false;
    }

    public OutPatient(String firstName, String lastName, int healthCardNumber,
                      double distanceFromClinic, boolean mobility) {
        super(firstName, lastName, healthCardNumber);
        this.distanceFromClinic = distanceFromClinic;
        this.mobility = mobility;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;//1
        if (o == null || getClass() != o.getClass()) return false;//2
        if (!super.equals(o)) return false;//3
        OutPatient that = (OutPatient) o;//4
        //5
        return Double.compare(that.distanceFromClinic, distanceFromClinic) == 0 &&
                mobility == that.mobility;
    }

    @Override
    public int hashCode() {

        return Objects.hash(super.hashCode(), distanceFromClinic, mobility);
    }
}

LEAVE A REPLY

Please enter your comment!
Please enter your name here