Sunday 12 February 2012

Implementing hashCode() and equals()


The methods hashCode() and equals() play a distinct role in the objects you insert into Java collections. The specific contract rules of these two methods are best described in the JavaDoc. Here I will just tell you what role they play. What they are used for, so you know why their implementations are important.

Few Thump rules:
  • If two objects are same then they must return same value in hashcode() and equals() method whenever invoked.
  • It is not necessary that two different object must have different hashcode values. it might be possible that they share common hash bucket.
JVM assigns unique hashcode value to each object when they are created in memory and if developers don’t override the hashcode method then there is no way the two object returns same hashcode value.
As the question comes in your mind that equals() method is used to compare objects that they are having same value or not but why should we override the hashcode method ?
The answer to the question is for the hash technique based data structures like HashMap and HashTable.
As you can see in above diagram that every object is placed in Hash bucket depending on the hashcode they have. It is not necessary that every different object must have different hashcode. hashcode is used to narrow the search result. When we try to insert any key in HashMap first it checks whether any other object present with same hashcode and if yes then it checks for the equals() method. If two objects are same then HashMap will not add that key instead it will replace the old value by new one.
What will happen if I don’t override the hashcode method?
Ans : If the object does not implement hashcode() method and used as key then we will not get the object back as shown in below code.
Code without implementation of equals() and hashcode()
package org.opensourzesupport;

import java.util.HashMap;

class Movie {

    private String name, actor;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getActor() {
        return actor;
    }

    public void setActor(String actor) {
        this.actor = actor;
    }

    public int getReleaseYr() {
        return releaseYr;
    }

    public void setReleaseYr(int releaseYr) {
        this.releaseYr = releaseYr;
    }
    private int releaseYr;
}

public class HashMapDemo {

    public static void main(String[] args) {

        Movie m = new Movie();
        m.setActor("Akshay");
        m.setName("Thank You");
        m.setReleaseYr(2011);

        Movie m1 = new Movie();
        m1.setActor("Akshay");
        m1.setName("Khiladi");
        m1.setReleaseYr(1993);

        Movie m2 = new Movie();
        m2.setActor("Akshay");
        m2.setName("Taskvir");
        m2.setReleaseYr(2010);

        Movie m3 = new Movie();
        m3.setActor("Akshay");
        m3.setName("Taskvir");
        m3.setReleaseYr(2010);

        HashMap<Movie, String> map = new HashMap<Movie, String>();
        map.put(m, "ThankYou");
        map.put(m1, "Khiladi");
        map.put(m2, "Tasvir");
        map.put(m3, "Duplicate Tasvir");

        //Iterate over HashMap
        for (Movie mm : map.keySet()) {
            System.out.println(map.get(mm).toString());
        }

        Movie m4 = new Movie();
        m4.setActor("Akshay");
        m4.setName("Taskvir");
        m4.setReleaseYr(2010);

        if (map.get(m4) == null) {
            System.out.println("----------------");
            System.out.println("Object not found");
            System.out.println("----------------");
        } else {
            System.out.println("----------------");
            System.out.println(map.get(m4).toString());
            System.out.println("----------------");
        }
    }
}
Output: Khiladi Tasvir ThankYou Duplicate Tasvir —————- Object not found —————-
As you can see in above program :
  1. Duplicate objects are added in Hashmap as a key (Because we have not overided the hashcode and equals method)
  2. We are not able to get back object from map (Because hashcode is not implemented)

Same program with equals and hashcode implementation:
package org.opensourzesupport;

import java.util.HashMap;

class Movie {

    private String name, actor;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getActor() {
        return actor;
    }

    public void setActor(String actor) {
        this.actor = actor;
    }

    public int getReleaseYr() {
        return releaseYr;
    }

    public void setReleaseYr(int releaseYr) {
        this.releaseYr = releaseYr;
    }
    private int releaseYr;

    @Override
    public boolean equals(Object o) {
        Movie m = (Movie) o;
        return m.actor.equals(this.actor) && m.name.equals(this.name) && m.releaseYr == this.releaseYr;
    }

    @Override
    public int hashCode() {
        return actor.hashCode() + name.hashCode() + releaseYr;
    }
}

public class HashMapDemo {

    public static void main(String[] args) {

        Movie m = new Movie();
        m.setActor("Akshay");
        m.setName("Thank You");
        m.setReleaseYr(2011);

        Movie m1 = new Movie();
        m1.setActor("Akshay");
        m1.setName("Khiladi");
        m1.setReleaseYr(1993);

        Movie m2 = new Movie();
        m2.setActor("Akshay");
        m2.setName("Taskvir");
        m2.setReleaseYr(2010);

        Movie m3 = new Movie();
        m3.setActor("Akshay");
        m3.setName("Taskvir");
        m3.setReleaseYr(2010);

        HashMap<Movie, String> map = new HashMap<Movie, String>();
        map.put(m, "ThankYou");
        map.put(m1, "Khiladi");
        map.put(m2, "Tasvir");
        map.put(m3, "Duplicate Tasvir");

        //Iterate over HashMap
        for (Movie mm : map.keySet()) {
            System.out.println(map.get(mm).toString());
        }

        Movie m4 = new Movie();
        m4.setActor("Akshay");
        m4.setName("Taskvir");
        m4.setReleaseYr(2010);

        if (map.get(m4) == null) {
            System.out.println("----------------");
            System.out.println("Object not found");
            System.out.println("----------------");
        } else {
            System.out.println("----------------");
            System.out.println(map.get(m4).toString());
            System.out.println("----------------");
        }
    }
}
Output: Khiladi Duplicate Tasvir ThankYou —————- Duplicate Tasvir —————- As you can see :
  • Duplicate Keys are not added instead there values are replaced.
  • Now the object is retrieved from the Map.







No comments:

Post a Comment