Thursday 19 June 2014

hashCode and equals

Lets understand with a small example where and why hashCode and equals are used.


Java.lang.Object has methods called hasCode() and equals(). These methods play a significant role in the real time application. However its use is not always common to all applications. In some case these methods are overridden to perform certain purpose. I will explain you some concept of these methods and why it becomes necessary to override these methods.



Lets say, you have a Map containing employees object as the key and String as value. Eg: Map<Employee,String> where Employee Object -> EmpId,EmpName,Age. Lets assume there are many entries in the map and you want to find if two  employee objects are equal. So following will be the basic implementation of a java developer.




package com.test;

public class Employee {

String EmpName;
int EmpNo;
int age;
public Employee(String EmpName,int EmpNo,int age) {
this.EmpName = EmpName;
this.EmpNo = EmpNo;
this.age = age;
}

public static void main(String[] args) {
/* 3 Employee Objects Created and checking if e1 and e3 objects are equal */
Employee e1 = new Employee("Sri",02,27);
Employee e2 = new Employee("Priya",03,28);
Employee e3 = new Employee("Sri",02,27);
/* e1 and e3 objects will not be equal */
System.out.println("Are E1 and E3 equal:" +e1.equals(e3));
System.out.println("e1 hash code:" +e1.hashCode());
System.out.println("e2 hash code:" +e2.hashCode());
System.out.println("e3 hash code:" +e3.hashCode());
}
}
Output:
Are E1 and E3 equal:false
e1 hash code:28117098
e2 hash code:17008065
e3 hash code:4354460


Why did it return false. As per the above code,e1 and e3 objects seem to have the same values in the Employee Object and hence it should be equal right? 
Whenever we create a object, JVM allocates a memory/address space on the heap for the object. Object generates a HashCode based on the memory address of the instance of the object. This hash code generation is done internally and need not worry about the generation. For us, hashCode is just a random number generated by the JVM. 
So in this case, e1 will have one hashcode generated ad e2 will have another hashcode generated and e3 will have another hashcode generated. So, when we say e1.equals(e3), it checks if e1 hashcode is equal to e3 hashcode. It will be different and hence it returned false. It checks if two different objects are equal.

What can we do to overcome this situation? We can generate hashcode of our own with any logic of developer choice and check the equality which will result in a positive scenario.
   package com.test;
   public class Employee {
String EmpName;
int EmpNo;
int age;
public Employee(String EmpName,int EmpNo,int age) {
this.EmpName = EmpName;
this.EmpNo = EmpNo;
this.age = age;
}
public int hashCode(){
int hashCode = EmpNo*age;
return hashCode;
}
public static void main(String[] args) {
/* 3 Employee Objects Created and checking if e1 and e3 objects are equal */
Employee e1 = new Employee("Sri",02,27);
Employee e2 = new Employee("Priya",03,28);
Employee e3 = new Employee("Sri",02,27);
/* e1 and e3 objects will not be equal */
System.out.println("Are E1 and E3 equal:" +e1.equals(e3));
System.out.println("e1 hash code:" +e1.hashCode());
System.out.println("e2 hash code:" +e2.hashCode());
System.out.println("e3 hash code:" +e3.hashCode());
}
}
Output:
Are E1 and E3 equal:false
e1 hash code:54
e2 hash code:84
e3 hash code:54

Now, we have similar hashcodes generated with our logic but still e1 and e3 are unequal.Because, it uses java out of box equals method to check equality. There is a contract between the hashCode and equals that they have to go hand in hand else you may encounter issues. So, whenever we implement hashCode method, we will also implement equals method. Lets write a equals method now. Lets say, if empId is unique in e1 and e3, we will declare that they are equal and will return a boolean true/false.

package com.test;
public class Employee {
String EmpName;
int EmpNo;
int age;
public Employee(String EmpName,int EmpNo,int age) {
this.EmpName = EmpName;
this.EmpNo = EmpNo;
this.age = age;
}
public int hashCode(){
int hashCode = EmpNo*age;
return hashCode;
}
public boolean equals(Object obj) {
boolean flag=false;
if(this.EmpNo == ((Employee)obj).EmpNo)
flag=true;
return flag;
}
public static void main(String[] args) {
/* 3 Employee Objects Created and checking if e1 and e3 objects are equal */
Employee e1 = new Employee("Sri",02,27);
Employee e2 = new Employee("Priya",03,28);
Employee e3 = new Employee("Sri",02,27);
/* e1 and e3 objects will not be equal */
System.out.println("Are E1 and E3 equal:" +e1.equals(e3));
System.out.println("e1 hash code:" +e1.hashCode());
System.out.println("e2 hash code:" +e2.hashCode());
System.out.println("e3 hash code:" +e3.hashCode());
}
}
Output:
Are E1 and E3 equal:true
e1 hash code:54
e2 hash code:84
e3 hash code:54


We have got the two objects equal now. So, Whenever there is any Object equality check, we should implement hashCode and equals method to avoid problems with Object manipulations/retrievals. 

Hope this post helps.

0 comments:

Post a Comment