Thursday, June 12, 2008

Implementing Equals and HashCode

In my last blog i described how we can compare two java objects of same class by overriding equals method. In this blog i will explain best practices regarding implementing of equals method.
Whenever, we go for overriding of equals method, one question comes to our mind is, on which basis we will have to say that two objects are same. First answer comes to mind is that we should compare objects on the basis of primary key which is also used to distinguish the records in the database. Primary keys are good candidate to compare objects if we assign primary keys ourself not by database. When primary key is assigned by database like auto number, objects don't have primary key until they are persisted in the database so before persistent of objects, how we should compare the objects. Good practice is always compare objects on the basis of business key which uniquely describes objects. Suppose we have a class of Person with attributes (id, name, ssn,address) . In this class we have two unique attributes one is id and second one is ssn. id is used to distinguish the objects in the database and is assigned when objects are persisted, then only choice is SSN which we can use to compare different person because each person has his own SSN (Social Security Number). So best practice is always compare objects on business keys rather than on database keys.
Second best practice is whenever you go for overriding of equals method. also override "int hashCode()" method. This method returns hash of objects. Implementing hasCode facilitates us when we use objects as keys in HashTable. If we don't override hashCode method, each object created with new operator will always has different hash values irrespective of fact whether they are same or not. Suppose I have a class of Customer with attributes (id, name, ssn, address) and i create two objects with new operation having the same dataset. Although logically they are same but physically they are two different objects that's y they have differnt hashCode. So best practice is that if two objects are equals, then those two objects should always have same hashCode. Overriding of hashCode will also facilitate us when we save objects in sets. Sets store only one instance of an object at a time, so if we have two customer objects with same attributes, then only one instance of customer must be saved in sets. It is only possible by overriding of hashcode method.
Now question is how to generate hashCode for an object. Answer is same as for equals method. Always generate hashCode from business keys. In above example of Customer objects, we should generate hashCode of Customer from SSN. java has provided methods which generate hashCode for all primitive data types and for String. hashCode for primitive data types are generated by using wrappers of primitive data types e.g. for int we can generate hashCode by following code:

Integer i = new Integer(5);
int code = i.hashCode();

Similary we can get hashCode of other primitive datatypes by using respective wrapper classes.

So in this blog we have come to Two Best Practices regarding comparison of objects:
- One is always compare objects in equal method on the basis of business keys.
- Second is whenever override equals method, also override hashCode method and generate hash for objects on the basis of same business key as used in equals method.

4 comments:

SACHIN JAIN said...

These is good enough for interview point of view but implementation can't be done for these

Anonymous said...

Nice article but I believe its important to understand the consequences of not following this contract as well and for that its important to understand application of hashcode in collection classes e.g. How HashMap works in Java and how hashcode() of key is used to insert and retrieve object from hashMap.

Javin

Anil Nivargi said...
This comment has been removed by the author.
Anil Nivargi said...

so why i get such output?

import java.util.HashMap;
public class StudentDemo {

String name;
int id;
public StudentDemo() {

name = null;
id = 0;

}
public StudentDemo( String name , int id){

this.name = name;
this.id = id;
}
public static void main(String arh[]){

StudentDemo s1 = new StudentDemo("shramik",121);
StudentDemo s2 = new StudentDemo("rohit",122);
StudentDemo s3 = new StudentDemo("suresh",123);
StudentDemo s4 = new StudentDemo("karan",124);
StudentDemo s5 = new StudentDemo("pratik",125);
StudentDemo s6 = new StudentDemo("mohan",126);

//System.out.println(s1.hashCode()+" "+s2.hashCode()+" "+s3.hashCode()+" "+s4.hashCode()+" "+s5.hashCode()+" "+s6.hashCode());

HashMap hm = new HashMap();

hm.put(s1,"8982xxxxxx");
hm.put(s2,"8934xxxxxx");
hm.put(s3,"9922xxxxxx");
hm.put(s4,"9835xxxxxx");
hm.put(s5,"8089xxxxxx");
hm.put(s6,"5678xxxxxx");
hm.put(new StudentDemo("abc",127),"8934xxxxxx");

System.out.println(hm.get(s1));
System.out.println(hm.get(s2));
System.out.println(hm.get(s3));
System.out.println(hm.get(s4));
System.out.println(hm.get(s5));
System.out.println(hm.get(s6));
System.out.println(hm.get(new StudentDemo("abc",127)));


}
}
o/p:-
8982xxxxxx
8934xxxxxx
9922xxxxxx
9835xxxxxx
8089xxxxxx
5678xxxxxx
null


i am not override the hashCode() and equals() method also i invoke get(key) method on hashmap object i get respected value but for last key not why?