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); } }