dineshonjava

hashCode() and equals() methods in Java

hashCode() and equals() methods in Java

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.

equals() method understanding:
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.
Popular Spring Tutorials
  1. Spring Tutorial
  2. Spring MVC Web Tutorial
  3. Spring Boot Tutorial
  4. Spring JDBC Tutorial
  5. Spring AOP Tutorial
  6. Spring Security Tutorial
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


hashCode() method Understanding:

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().

  • First if you want to override the equals() method, then you have to override the hashCode() method as well.
  • Second if two objects are equal, their hash code values must be equal as well.
  • And if two objects are not equal, their hash code values can be equal or not.
  • And if two objects have identical hash codes, they can be equal or not.
  • And if two objects have different hash codes, they must not be equal.
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:

  • The equals() method compares the two objects are equal by value of data member of class i.e semantically.
  • The hashCode() method returns an integer value which is the logical number of memory address and it used to store elements in
  • buckets of a hashtable-based collection.
  • When the equals() method is overridden then the hashCode() method must be overridden as well.
  • If equals() method return true then their hash codes must be equal.
  • If equals() method return false then their hash codes can be equal or not.
  • If their hash codes are equal then equal() may return true or false.
  • If their hash codes are not equal then equal() must return false.