A HashMap implements Map interface.In a Map structure , data is storing as key value pairs.HashMap is simply unordered and unsorted map structure.The hasCode() method plays an important role when we are using objects of our own classes as keys in a HashMap . The efficiency of our structure depends on the hashCode() implementation of the class. We should override the hashCode() and equals() methods too.For more details about hashCode() and equals() Click here.
Now let us see an example class which uses HashMap for storing data.This example shows how we can put , iterate and delete data from a HashMap. Here we are using String objects as keys as well as values.
import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; public class HashMapSample { Map map = null; public HashMapSample() { } public void addItemsToMap() { System.out.println("Adding contents to map "); map = new HashMap(); String[] listItems = {"dog", "cat", "cow", "elephant", "sheep"}; for (int i = 0; i < listItems.length; i++) { map.put(listItems[i] + i, listItems[i]); } } public void displayMap() { System.out.println("Displaying contents of map"); Set set = map.entrySet(); System.out.println("Size = "+set.size()); Iterator i = set.iterator(); while (i.hasNext()) { Map.Entry entry = (Map.Entry) i.next(); System.out.print(entry.getKey() + ": "); System.out.println(entry.getValue()); } } public void removeItems() { map.clear(); System.out.println("Displaying contents after removal:"); displayMap(); } public static void main(String[] args) { HashMapSample sample = new HashMapSample(); sample.addItemsToMap(); sample.displayMap(); sample.removeItems(); } }
As we discussed , the data is storing in a HashMap in random order.The order of insertion is not preserving.This can be verified after analyzing the output.
Output
Adding contents to map
Displaying contents of map
Size = 5
sheep4: sheep
cat1: cat
cow2: cow
elephant3: elephant
dog0: dog
Displaying contents after removal:
Displaying contents of map
Size = 0
So this verifies our concept.
Objects of our own classes as keys in HashMap
As we already discussed efficiency of a HashMap depends on the hashCode() implementation . If we want to use objects of our own classes as keys then we should override hashCode() method . If we are not overriding the hashCode() method , that means we are using the hashCode() implementation of the super class (java.lang.Object).This default implementation gives different hash code values for all the objects.Even the meaningfully same objects are getting two hash codes. So meaningfully same objects will be treated as different objects. So we should override the hashCode() method in our class in such a way that such meaningfully same objects are getting the hash code value.In addition to overriding the hashCode() we need to override the equals() method too .Let us examine this concept with suitable examples.
case 1. Without overriding hashCode() and equals()
So as explained earier , here we are using the default hashCode() and equals() of java.lang.Object super class. So even if create two objects with exactly same attribute values , both are getting different hash codes. So two objects are treating as different. If try to add these objects as keys in HashMap , then two objects will be added as keys.It is a duplication. Because those two keys are having exactly same attribute values ,which means those objects are meaningfully equal.
Also if we are using the default implementation of hashCode() and equals() , then searching for a particular key is also not effective.
Now let us see our Student.java class.Objects of this class needs to be used as keys in our HashMap.
public class Student { private int rollNumber; private String name; public Student(int number, String name) { this.rollNumber = number; this.name = name; } public int getRollNumber() { return rollNumber; } public void setRollNumber(int rollNumber) { this.rollNumber = rollNumber; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String toString(){ return "Roll Number : "+getRollNumber() +" ; Name : "+getName(); } }
Now let us see our Main.java.
import java.util.HashMap; import java.util.Map; public class Main { private Map<Student, String> map = null; public Main() { map = new HashMap<Student, String>(); } public void addItems() { Student student1 = new Student(1, "Bijoy"); Student student2 = new Student(2, "Dexter"); Student student3 = new Student(1, "Bijoy"); map.put(student1,"First"); map.put(student2,"Second"); map.put(student3,"Third"); System.out.println("Size of Map = "+map.size()); } public void display() { Student student = new Student(1,"Bijoy"); System.out.println("Is present or not ? "+map.containsKey(student)); } public static void main(String[] args) { Main main = new Main(); main.addItems(); main.display(); } }
In the addItems() method , our student1 and student3 objects are meaningfully same.But we are not overriding hashCode() .So both will be treated as different objects.So size of Map will be 3 .Also in display() method we are creating an object its attribute values are same as that of one existing in the Map.But both those objects are having different hash codes.So the search also returns false.Let us verify the output.
Output
Size of Map = 3
Is present or not ? false
case 2.By overriding hashCode() and equals()
Now let us change our Student.java by overriding hashCode() and equals() methods.It never permits addition of duplicate keys.Also search with meaningfully same object of one existing in Map also returns true.
public class Student { private int rollNumber; private String name; public Student(int number, String name) { this.rollNumber = number; this.name = name; } public int getRollNumber() { return rollNumber; } public void setRollNumber(int rollNumber) { this.rollNumber = rollNumber; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String toString(){ return "Roll Number : "+getRollNumber() +" ; Name : "+getName(); } public int hashCode(){ return getRollNumber(); } public boolean equals(Object object){ Student student = (Student)object; boolean status = false; if(getRollNumber() == student.getRollNumber() && getName().equalsIgnoreCase(student.getName())){ status = true; } else{ status = false; } return status; } }
Use the same Main.java of case 1 here also .Now run the Main.java.The output makes our assumptions strong.
Output
Size of Map = 2
Is present or not ? true