Learnerslesson
   JAVA   
  SPRING  
  SPRINGBOOT  
 HIBERNATE 
  HADOOP  
   HIVE   
   ALGORITHMS   
   PYTHON   
   GO   
   KOTLIN   
   C#   
   RUBY   
   C++   




Java - equals() & hashCode() with HashMap

When an object(Say a String "John") is added to the HashMap with a key (Say '1') using the put() method,

i.e. myHashMap.put(1,"John")

So, the HashCode is calculated based on the key (i.e. '1').


What is the use of this HashCode?

Now, a memory location is calculated based on the HashCode and that Key (i.e. '1') along with the value ('John') is added to that particular memory location.

Sounds complex!! Let's make it simple.

For the below statement,


myHashMap.put(1,"John");

The HashCode is calculated based on the key (i.e. '1'). Say the calculated HashCode is 6. So, the Key (i.e. '1') and the value (i.e. 'John') will get added to the 6th location of memory.

Again for the below statement,


myHashMap.put(2,"Paul");

The HashCode is calculated based on the key (i.e. '2'). Say the calculated HashCode is 3. So, the Key (i.e. '2') and the value (i.e. 'Paul') will get added to the 3rd location of memory.

java_HashCode_HashMap


But why do we have to calculate the Hash Code?

Note : Java calculates hashCode() based on the object reference. i.e. Based on the memory location of the object.

So far we were dealing with the keys as Integers.

i.e. myHashMap.put(1,"John");

Now, let us consider a scenario where there is a 'Human' class, which contains the 'name' and 'age' of a person.


class Human{

  int age;
  String name;

  -- getters, setters and constructors ---

}

And, we have to associate an address with the 'Human' class. i.e. We have to create a HashMap where 'Human' object will be a Key and the name of the city will be the Value.

i.e. hashMap.put(human1,"Mumbai");

Now, let us look at the below example to understand the scenario better.


public class TestCollection{
  public static void main(String[] arg){

  Human human1 = new Human(21,"Sham");
  Human human2 = new Human(42,"Paul");

  // We will be adding these Human objects as keys to the HashMap.
  Map hashMap = new HashMap(); // Declare an HashMap.
  hashMap.put(human1,"Mumbai"); // Add the Human objects to the HashMap along with address.
  hashMap.put(human2,"Bangalore");


  // Below code creates a new object which has the details of 'Paul'.
  Human human3 = new Human(42,"Paul");
  hashSet.put(human3,"Kolkata");
  }
}

So, what we have done in the above example is:

1) Created two Human objects


Human human1 = new Human(21,"Sham");
Human human2 = new Human(42,"Paul");

2) Declare a HashMap and add the Human objects to the HashMap.


Map hashMap = new HashMap();
hashMap.put(human1,"Mumbai");
hashMap.put(human2,"Bangalore");

3) We are creating a new object 'human3' for holding the details of 'Paul'.


Human human3 = new Human(42,"Paul");

4) We have added the object 'human3' to the HashMap.


hashSet.put(human3,"Kolkata");

But 'human3' contains the details of 'Paul' whose age is '42'. And if we see closely 'Paul' is already in the hashSet, since we have already added 'human2' object.So, the duplicate entry is getting inserted in the HashSet. But why?

Let's understand the cause:


How does a Map prevents duplicate Key entries while insertion?

Map internally takes the help of equals() method to check for duplicate Keys.

And if you remember equals() compares the objects by reference. i.e. By its memory location.

Now, when we are trying to insert an object( 'human4' in the above case), java takes the help of equals() method to check by the memory location of the object.

In simple words the equals() method does not check what is stored inside the Object. It only checks if two objects belongs to the same memory location.


How to solve this problem?

The Solution is, we have to override hashCode() and equals() method in our class.

Let us redefine the hashCode() and equals() in the Human class.


class Human{

  int age;
  String name;

  -- getters, setters and constructors ---

  @Override
  public boolean equals(Object object) {

    Human human = (Human) object;

    if(human.getAge() == age && human.getName().equals(name))
      return true;
    else
      return false;
    }

  @Override
  public int hashCode() {
    int value;
    value = age + name.hashCode();

    return value;
  }

}

We have redefined the equals() method where we have mentioned that the objects should be compared based on value and not on memory location.

Also we have overridden the hashCode() method and put a custom logic. So that the hash code is calculated not based on the memory location(Since the default implementation of hashCode() calculates the hash code based on the memory location).


Note : Remember that HashMap calculates the HashCode based on the Key and not the Value.