Thursday, 30 January 2014

Overridding equals and hashCode methods

According to the equal contract, If two objects are equal then hashCode of those two objects must return same integer.

If two objects are unequal there hashCode may or may not be same.

It is not neccessary overriding both at all time, But if you think to override one then you must override the other one too..

The problem occurs when we work with HashMap and Hashtables

In our previous post, Hashmap machanism we discussed that HashMap assigns key object hashCode to the bucket as identity. When we retrieve value from HashMap it finds the hashCode of the key and returns the value.
(Note: hashCode is nuthing but an integer number, by converting object memory address to an integer)

Lets see why to override both equals and hashCode methods.
in this below example, i am overriding only equals mehtod

public class Customer{
int id;
String name;
public Customer(int id, String name)
{
this.id = id;
this.name = name;
}
@Override
public boolean equals(Object obj) {
System.out.println("Calling");
if(null == obj)
return false;
if(!(this.getClass() == obj.getClass()))
return false;
if(!(this.id == ((Customer)obj).id && this.name.equals(((Customer)obj).name))
return false;
return true;
}
public static void main(String[] args) {
Customer customer = new Customer(1, "Prasad");
HashMap<Object, Object> map = new HashMap<Object, Object>();
map.put(customer, new String("123"));
System.out.println(map.get(new Customer(1, "Prasad"))); // returns null
}
}

In the above example, i am assigning Customer object as key and retrieves with the same Customer object. Eventhough i am retrieving with the new object, according to my equals method the two objects(storing and retrieving) are equal. because i am performing equality by overriding equals method, and based on the id and name it is performing equality.

The HashMap results null, because the two same objects has the different hashCodes.

So i must override hashCode method along with the equals method.

Now in this below example
public class Customer{
int id;
String name;
public Customer(int id, String name)
{
this.id = id;
this.name = name;
}
@Override
public boolean equals(Object obj) {
System.out.println("Calling");
if(null == obj)
return false;
if(!(this.getClass() == obj.getClass()))
return false;
if(!(this.id == ((Customer)obj).id && this.name.equals(((Customer)obj).name))
return false;
return true;
}
      @Override
public int hashCode() {
int num = 3;
return num*this.name.hashCode();
}
public static void main(String[] args) {
Customer customer = new Customer(1, "Prasad");
HashMap<Object, Object> map = new HashMap<Object, Object>();
map.put(customer, new String("123"));
System.out.println(map.get(new Customer(1, "Prasad"))); // returns 123
}
}

Now it returns the value as 123.

Because here the hashCodes are same for same equal objects.

No comments:

Post a Comment

Followers