HashMap with custom keys
So far, we have only seen java language api classes such as String, Integer as keys in map. What if we want to add custom objects as keys in our hash map. We need to make sure following things if we want to add custom keys in a map.
- The class whose objects we want to use as keys in map must override equals() and hashcode() methods from Object class.
- The keys should be immutable. It means we should make the class immutabel whose objects we want to use as keys.
equals() and hashCode() contract
equals() and hashCode() both methods are part of Object class which is parent of all the classes in Java language. Both of these methods have default implementation. But if we want to compare custom objects, we must override these methods to tell when two objects of our class would be considered equal.
General contract is that if two objects are equal, they must return the same hashcode. Let’s see other points of equals() and hashcode() contract
- Whenever hashcode() is invoked on the same object more than once during execution of a Java application, it must consistently return the same hash code, given that no information used in equals() method on the object is modified. Hash code may change in various executions of the same java program.
- If two objects are equal according to the equals() definition, they must return the same hash code.
- If two objects are not equal according to equals() definition, it is not necessary for them to return the different hash code as well. However, returning different hash code will improve the performance of map/hashtable.
What if we do not override equals() method
For that we need to understand the default implementation of equals() method. So, the default implementation says that the two objects would be considered equal when their addresses are equal, meaning when both of them are pointing to exactly same object.
This is why it is necessary to override equals() method.
What if we do not override hashCode() method
If we do not override hashCode() method, the default will always return a new hash even for the object which have same attribute values. So, objects will always have different hashcodes and thus can never be equal. In such cases, even logically duplicate objects will be considered unique. And thus, the hash map will not work as expected.
How to override equals() and hashCode() methods
Either we can write our own implementation of equals() and hashCode(), or we can use our IDE’s help to generate them. In eclipse/STS, right click on the class, go to ‘Source’, and then choose option ‘Generate hashCode() and equals()’ to auto generate them. Have a look at these methods and understand how you can write your own implementation of these methods.
Creating HashMap using custom keys
In the below example, we are going to create a class of actors and use them as keys in our hash map.
Actor class whose objects we will use as keys. Therefore, we have overridden equals() and hashcode() methods.
package com.javatrainingschool;
public class Actor {
private String name;
private int age;
public Actor(String name, int age) {
super();
this.name = name;
this.age = age;
}
//getters and setters methods
@Override
public String toString() {
return "Actor [name=" + name + ", age=" + age + "]";
}
// hashCode implementation
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
//equals implementation
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Actor other = (Actor) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
Example class with main method
package com.javatrainingschool;
import java.util.HashMap;
import java.util.Map;
public class HashMapWithCustomKeysExample {
public static void main(String[] args) {
Actor a1 = new Actor("Johhny Depp", 58);
Actor a2 = new Actor("Madhuri Dixit", 54);
Actor a3 = new Actor("Will Smith", 53);
Actor a4 = new Actor("Shah Rukh Khan", 55);
//this map stores actor as a key and the industry he/she belongs to as a value
Map<Actor, String> map = new HashMap<Actor, String>();
map.put(a1, "Hollywood");
map.put(a2, "Bollywood");
map.put(a3, "Hollywood");
map.put(a4, "Bollywood");
String industry = map.get(a3);
System.out.println(a3 + " belongs to " + industry);
}
}
Output :
Actor [name=Will Smith, age=53] belongs to Hollywood