Undestanding hashCode() and equals() on using Map



Understand hashCode() and equals() in HashMap

Always remember that when you are using a class that implements Map or any classes that you
are using as a part of the keys for that map must override the hashCode() and equals()
methods.

Let's see the following example....


-----------------------------------
import java.util.*;


class MapEQ2 {
  public static void main(String[] args) {
       Map<ToDos, String> m = new HashMap<ToDos, String>();
       
       ToDos t1 = new ToDos("Monday");
       ToDos t2 = new ToDos("Monday");
       ToDos t3 = new ToDos("Tuesday");
       System.out.println("Putting first object::");
       m.put(t1, "doLaundry");
       System.out.println("\n Putting second object::");
       m.put(t2, "payBills");
       System.out.println("\n Putting third object::");
       m.put(t3, "cleanAttic");
       System.out.println("\n Map size ::"+m.size());
       System.out.println("\n Map ::: "+m.toString());
  } 
}


class ToDos{
  String day;
  ToDos(String d) { day = d; }
  public boolean equals(Object o) {
      System.out.println("calling equals()..");
     return ((ToDos)o).day == this.day;
  }
/*
   public int hashCode() { 
     System.out.println("calling hashcode()..");
    return 9;
   }


*/
}
-----------------------------------------

See the output:

C:\SCJP6\collection>javac "MapEQ2.java"


C:\SCJP6\collection>java MapEQ2
Putting first object::
Putting second object::
Putting third object::
Map size ::3
Map ::: {ToDos@addbf1=payBills, ToDos@42e816=cleanAttic, ToDos@19821f=doLaundry}


Here you see there is no call to equals method while putting objects on map, because here you have commented hashCode() method. It just calls to default hashCode() method which will generate different keys and so there will be no call to equals method. It calls first to hashCode() and then if it gets duplicate key then it calls to equals() method.

Now if you de-comment the hashCode() method.....

------------------------------------------------
import java.util.*;


class MapEQ2 {
  public static void main(String[] args) {
       Map<ToDos, String> m = new HashMap<ToDos, String>();
       
       ToDos t1 = new ToDos("Monday");
       ToDos t2 = new ToDos("Monday");
       ToDos t3 = new ToDos("Tuesday");
       System.out.println("Putting first object::");
       m.put(t1, "doLaundry");
       System.out.println("\n Putting second object::");
       m.put(t2, "payBills");
       System.out.println("\n Putting third object::");
       m.put(t3, "cleanAttic");
       System.out.println("\n Map size ::"+m.size());
       System.out.println("\n Map ::: "+m.toString());
  } 
}


class ToDos{
  String day;
  ToDos(String d) { day = d; }
  public boolean equals(Object o) {
      System.out.println("calling equals()..");
     return ((ToDos)o).day == this.day;
  }


   public int hashCode() { 
     System.out.println("calling hashcode()..");
    return day.length();
   }




}
------------------------------------------
Now see the output:

C:\SCJP6\collection>javac "MapEQ2.java"


C:\SCJP6\collection>java MapEQ2
 Putting first object::
 calling hashcode()..


 Putting second object::
 calling hashcode()..
 calling equals()..


 Putting third object::
 calling hashcode()..
 calling equals()..


 Map size ::2
 calling hashcode()..
 calling hashcode()..


 Map ::: {ToDos@9=cleanAttic, ToDos@9=payBills}


Here you can see that first it call to hashCode() method and then call tom equals and see if that object is used as key already, then it will overwrite to duplicate key with value for that object. So we get only  two objects this time.

In real-life hashing, it’s not uncommon to have more than one entry in a bucket. Hashing retrieval is a two-step process.


1. Find the right bucket (using hashCode())
2. Search the bucket for the right element (using equals() ).

So be carefull about key when you are going to insert some value in HashMap. Always override hashCode() and equals() method properly.
----------------------------------------

Now change the hashCode() method and compile and run again this program:

public int hashCode() { 
     System.out.println("calling hashcode()..");
    return day.length();
   }

-----------------------------------
This time hashCode() is returning length of day as a hashcode.

See here again output::

C:\SCJP6\collection>javac "MapEQ2.java"


C:\SCJP6\collection>java MapEQ2
Putting first object::
calling hashcode()..


Putting second object::
calling hashcode()..
calling equals()..


Putting third object::
calling hashcode()..


Map size ::2
calling hashcode()..
calling hashcode()..


Map ::: {ToDos@6=payBills, ToDos@7=cleanAttic}

So here what happens, First it put first object ("Monday","doLaundry").
Now when it comes to second ("Monday","payBills"), then it sees the same hashCode and then it calls to equals() method and then in overwrite to the first one object.

In third Map (key,value) object ("Tuesday","cleanAttic"), it sees differnet key and so it does not call equals and just insert it into map.

For any further help or suggestion, you can comment here....

Popular posts from this blog

Can not connect to git using ssh (Permissions 0644 for '/root/.ssh/id_rsa' are too open.

Upload file on Google cloud storage using Java servlet on google app engine

Android: where to run keytool command in android