Wednesday 30 November 2016

HashCode and Equals method in Java object

HashCode and Equals method in Java object | Java Source World




HashCode and Equals method in Java object – A programmatic concept:



Object class provides two methods hashcode() and equals() to represent the identity of an object. It is a common convention that if one method is overridden then other should also be implemented.

Before explaining why, lets see what is the contract between these two methods hold. As per the Java API documentation:

Whenever hashcode 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(object) 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 (Java.lang.Object) 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 hashtables.


Now we will see the programmatic representation of  hashcode() and equals() method.

Example:  Employee.java

Employee is an customized object in java and where we don't have hashcode() and equls() method implementation.


package com.javasourceworld.corejava.map;

public class Employee {

       private int empAge;
       private String empName;
       private double empSalary;
      
       public Employee(int age, String name, double salary){
              this.empAge = age;
              this.empName = name;
              this.empSalary = salary;
       }

       public int getEmpAge() {
              return empAge;
       }

       public void setEmpAge(int empAge) {
              this.empAge = empAge;
       }

       public String getEmpName() {
              return empName;
       }

       public void setEmpName(String empName) {
              this.empName = empName;
       }

       public double getEmpSalary() {
              return empSalary;
       }

       public void setEmpSalary(double empSalary) {
              this.empSalary = empSalary;
       }
}
  

Now we will put the Employee object as a key in the map, remember we don't have hashcode() and equals() method implementation in the object.

MapTest.java


package com.javasourceworld.corejava.map;

import java.util.HashMap;
import java.util.Map;

public class MapTest {

       public static void main(String[] args) {
             
              Map<Employee, String> empMapObj = new HashMap<Employee, String>();
             
              empMapObj.put( new Employee(1,"Sachin",15600), "Emp_01");

              empMapObj.put( new Employee(2,"Sachin T",18600), "Emp_02");
             
              System.out.println("Set: "+empMapObj.entrySet());
             
              System.out.println("Get Key value: "+empMapObj.get(new                                                                           Employee(1,"Sachin",15600)));
             
       }

}


Lets run the above code and see the out put.

Output:

As shown in the above console, get(new mployee(1,"Sachin",15600))returns null value, even though  the entry set having two objects are available in the set.

Set: [com.javasourceworld.corejava.map.Employee@15db9742=Emp_01,com.javasourceworld.corejava.map.Employee@6d06d69c=Emp_02]

Null value will be displayed since the hashcode() method returns a different hash value for the Employee object created when we call for get(key) method and JVM tries to search for the object at different location.

Now we will see the map object in the debug mode, why the get(key) couldn't find the employee object even map exists with the proper keys.



As shown in the above screenshot, we can see the map object stored at 9th position in the table.

Now we will have a detail section of 9th position in the table.




As shown in the above screenshot, we can see that first object is stored with the hascode 517931593, and at next node one more entry is created and the second object stored in that location with the hashcode 91443719. 

As hascode and equals not implemented in the Employee object, when get(key) method called on map object empMapObj, its returned null value instead some value.

To retrieve the key corresponding value, we must override hashcode() and equals() method.

Now we will look run the same example after implementing the equals and hascode() methods in the Employee.java as below.

After adding the equals() and hascode() method, our Employee.java looks like below:


package com.javasourceworld.corejava.map;

public class Employee {
       private int empAge;
       private String empName;
       private double empSalary;
      
       public Employee(int age, String name, double salary){
              this.empAge = age;
              this.empName = name;
              this.empSalary = salary;
       }

       public int getEmpAge() {
              return empAge;
       }

       public void setEmpAge(int empAge) {
              this.empAge = empAge;
       }

       public String getEmpName() {
              return empName;
       }

       public void setEmpName(String empName) {
              this.empName = empName;
       }

       public double getEmpSalary() {
              return empSalary;
       }

       public void setEmpSalary(double empSalary) {
              this.empSalary = empSalary;
       }

       @Override
       public int hashCode() {
              final int prime = 31;
              int result = 1;
              result = prime * result + empAge;
              result = prime * result + ((empName == null) ? 0 : empName.hashCode());
              long temp;
              temp = Double.doubleToLongBits(empSalary);
              result = prime * result + (int) (temp ^ (temp >>> 32));
              return result;
       }

       @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 (empAge != other.empAge)
                     return false;
              if (empName == null) {
                     if (other.empName != null)
                           return false;
              } else if (!empName.equals(other.empName))
                     return false;
              if (Double.doubleToLongBits(empSalary) !=                                                          Double.doubleToLongBits(other.empSalary))
                     return false;
              return true;
       }

       @Override
       public String toString() {
              // TODO Auto-generated method stub
              return super.toString();
       }
}

Now we will run the MapTest.java once again and will see the result.

Console:


Now the get(key) method returned some value.

Now we will see the debug representation below:


As per above screen shot we can understand that at two different locations the two map objects are stored, hence while retrieving also using get(key) method that can easily find the bucket location and returns the value.






Other posts you may like to read:


Read More »