In java hashCode() and equals() methods have been defined in Object class which is parent class for java objects that means all classes in Java inherit these methods. Object class implements these methods for general purpose so you can also override these two methods on our custom classes.
Overriding of these methods is required some time when we use the classes whose objects are added to collections, especially the hashtable-based collections such as HashSet and HashMap.
As name suggest Object’s equals() method used for comparing two objects together, when java call equals() method if it return true it mean the two objects are equal or return false otherwise. But equals() method compare the two objects unlike using == operator in java. Object’s equals() method is define to compare two objects semantically i.e it compare value of member variable of objects, whereas the == operator compares two objects by comparing their references.
One thing to be note the default implementation of equals() method in the Object class compares references of two objects. That means we have to override it in our classes for semantic comparison. All wrapper classes like Integer, Double, Long, String etc implement the equals() method accordingly.
Let’s see below example for equals() method-
Here we are going two compare two string class object as following:
String s1 = new String("dinesh on java"); String s2 = new String("dinesh on java"); System.out.println("s1 == s2: " + s1 == s2); System.out.println("s1.equals(s2): " + s1.equals(s2));
Output of this code as below:
s1 == s2: false
s1.equals(s2): true
As we have discussed the reference comparison (== operator) returns false because s1 and s2 are two different objects which are stored in different locations in memory but the value comparison returns true because s1 and s2 has same value.
If instead of String class we could use Custom type object like Employee class’s objects we can compare by using overriding equals() method as below:
public class Employee { Integer empid; String name; Double salary; public Employee(Integer empid, String name, Double salary) { super(); this.empid = empid; this.name = name; this.salary = salary; } @Override public String toString() { return "Employee [empid=" + empid + ", name=" + name + ", salary=" + salary + "]"; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Employee other = (Employee) obj; if (empid == null) { if (other.empid != null) return false; } else if (!empid.equals(other.empid)) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; if (salary == null) { if (other.salary != null) return false; } else if (!salary.equals(other.salary)) return false; return true; } }
Let’s see test class for this method
public class Main { public static void main(String[] args) { Employee employee1 = new Employee(100, "Dinesh", 5000.0); Employee employee2 = new Employee(100, "Dinesh", 5000.0); Employee employee3 = new Employee(101, "Arnav", 6000.0); System.out.println("employee1 == employee2: " + (employee1 == employee2)); System.out.println("employee1.equals(employee2): " + (employee1.equals(employee2))); System.out.println("employee2.equals(employee3): " + (employee2.equals(employee3))); } }
Let see output of above Main class.
employee1 == employee2: false
employee1.equals(employee2): true
employee2.equals(employee3): false
Suppose you want to compare two objects of employee class, it will be considered equal if empid is same, for that we have to update the equals() method in the Employee class like this:
@Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Employee other = (Employee) obj; if (empid == null) { if (other.empid != null) return false; } else if (!empid.equals(other.empid)) return false; return true; }
Let’s see test class for this method
public class Main { public static void main(String[] args) { Employee employee1 = new Employee(100, "Dinesh", 5000.0); Employee employee2 = new Employee(100, "Arnav", 5000.0); System.out.println("employee1 == employee2: " + (employee1 == employee2)); System.out.println("employee1.equals(employee2): " + (employee1.equals(employee2))); } }
Let see output of above Main class.
employee1 == employee2: false
employee1.equals(employee2): true
This method returns a hash code value for this object. The Object class defines the hashCode() method as follows:
public int hashCode()
This method one logical integer number for every obhect when we call hashCode() method. This number known as hash number, it is used by hashtable-based collections like Hashtable, HashSet and HashMap to store objects in small containers called “backet”. In collection each bucket is associated with a hash code of object and bucket contains only objects having same hash code. In collection hash code value very helpful to searching on small parts of the collection instead the whole collection.
The default implementation of hashCode() in the Object class returns an integer number which is the logical memory address of the object. We can override it in our own classes.
The Contract Between equals() and hashCode()
There are following contracts between hashCode() and equals().
Example:
Let’s see how the hashCode() and equals() methods affect the behaviors of a Set as below codes.
public class Employee { Integer empid; String name; Double salary; public Employee(Integer empid, String name, Double salary) { super(); this.empid = empid; this.name = name; this.salary = salary; } @Override public String toString() { return "Employee [empid=" + empid + ", name=" + name + ", salary=" + salary + "]"; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Employee other = (Employee) obj; if (empid == null) { if (other.empid != null) return false; } else if (!empid.equals(other.empid)) return false; return true; } }
Here we have only equals() method is overridden till.
Now adding three employee objects two the Set collections as below.
import java.util.HashSet; import java.util.Set; public class Main { public static void main(String[] args) { Employee employee1 = new Employee(100, "Dinesh", 5000.0); Employee employee2 = new Employee(100, "Dinesh", 5000.0); Employee employee3 = new Employee(101, "Arnav", 6000.0); Set<Employee> set = new HashSet<Employee>(); set.add(employee1); set.add(employee2); set.add(employee3); for(Employee employee : set){ System.out.println(employee); } } }
Let see output of above Main class.
Employee [empid=100, name=Dinesh, salary=5000.0]
Employee [empid=101, name=Arnav, salary=6000.0]
Employee [empid=100, name=Dinesh, salary=5000.0]
Now in above class Employee overrides only the equals() method, the hashCode() method inherited from the Object class returns hashcode of each object which is not consistent with the equals() method. That is why the set treats the employee1 and employee2 object as two different elements.
So we have to override both methods equals() and hashCode() on each object to ensure there’s no duplication. Now, let’s override the hashCode() method in the Employee class to obey the contract of equals() and hashCode(). Here’s the code needs to be added:
@Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((empid == null) ? 0 : empid.hashCode()); result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((salary == null) ? 0 : salary.hashCode()); return result; }
Run the Main class code again to print the set and observe the result:
Employee [empid=101, name=Arnav, salary=6000.0]
Employee [empid=100, name=Dinesh, salary=5000.0]
Summary:
Strategy Design Patterns We can easily create a strategy design pattern using lambda. To implement…
Decorator Pattern A decorator pattern allows a user to add new functionality to an existing…
Delegating pattern In software engineering, the delegation pattern is an object-oriented design pattern that allows…
Technology has emerged a lot in the last decade, and now we have artificial intelligence;…
Managing a database is becoming increasingly complex now due to the vast amount of data…
Overview In this article, we will explore Spring Scheduler how we could use it by…