In this tutorial, we will learn the Java IdentityHashMap in detail and the differences between IdentityHashMap and HashMap.
IdentityHashMap uses reference equality rather than object equality while comparing the key (or values). In other words, in an IdentityHashMap
, two keys k1
and k2
are considered equal if and only if (k1==k2)
. We can use mutable keys in IdentityHashMap because reference equality doesn’t change with the object’s state.
1. Introduction to IdentityHashMap
The IdentityHashMap class (present in java.util package) is a HashTable-based implementation of Map Interface and has been present since Java version 1.4.
- This class is not a general-purpose Map implementation. Even though this class implements the Map interface, it violates Map’s general contract to use the equals() method when comparing objects. It uses reference equality (==) for searching the keys in the map. This class is used only wherein reference equality is required.
- IdentityHashMap internally uses the System.identityHashCode() method for computing
- IdentityHashMap has almost the same features as HashMap, including the constructors & methods. Still, as far as performance is concerned, it gives better performance when compared with HashMap as it uses the liner probe technique of HashTable as compared to the chaining technique used by HashMap.
- Its iterators throw ConcurrentModificationException while attempting to modify the map during the iteration.
- It is not a thread-safe class. Use Collections.synchronizedMap() to get a thread-safe reference of this class.
In Java Collections, the class has been declared as follows:
public class IdentityHashMap<K, V> extends AbstractMap<K, V> implements Map<K, V>, Serializable, Cloneable
As shown above, it implements Map
interface and extends AbstractMap
class.

2. Working with IdentityHashMap
2.1 Creating IdentityHashMap
We can create IdentityHashMap by making use of the following constructors:
IdentityHashMap()
: Used to create an empty map with the initial default capacity of 21.IdentityHashMap(int initialCapacity)
:
Used to create an empty map with the given initial capacity.IdentityHashMap(Map m)
:
Used to create a new IdentityHashMap with the same entries as the specified map.
IdentityHashMap<String, String> map = new IdentityHashMap<>();
IdentityHashMap<String, String> map = new IdentityHashMap<>(16);
Map<String, String> map = new HashMap<String, String>() {{
put("key1", "value1");
put("key2", "value2");
}};
IdentityHashMap<String, String> map = new IdentityHashMap<>(map);
2.2 IdentityHashMap Methods
Some of the frequently used methods present in this class are:
Object put(key, value):
Inserts a key-value pair into the map.Object get(key):
returns the value for the specified key in the map.boolean containsKey(key):
returnstrue
orfalse
based on whether the specified key is found in the map or not.boolean containsValue(value):
Similar to containsKey() method, it looks for the specified value instead of key.Set keySet():
returns the Set of all keys stored in the map.Set entrySet():
returns the Set of all mappings stored in the map.Value remove(Object key):
removes the key-value pair for the specified key.int size():
returns the map size equal to the number of key-value pairs stored in the map.
2.3 IdentityHashMap Example
Let’s quickly cover an example of creating its instance and how we can use the methods described above.
//Creating IdentityHashMap
IdentityHashMap<Integer, String> map = new IdentityHashMap<>();
//Adding values to map using put()
map.put(1, "A");
map.put(2, "B");
map.put(3, "C");
System.out.println(map);
//Getting a value from the map
String value = map.get(2);
System.out.println(value);
//Checking if a key or value present in the map
System.out.println(map.containsKey(3));
System.out.println(map.containsValue("Z"));
//Removing an entry
map.remove(3);
System.out.println(map);
//Finding map size
System.out.println(map.size());
//Iterating over the map
for(Map.Entry<Integer, String> entry : map.entrySet())
{
System.out.println(entry.getKey() + " :: " + entry.getValue());
}
Note that IdentityHashMap supports null
keys and values.
IdentityHashMap<String, String> map = new IdentityHashMap<>();
map.put(null, "Some Value"); //Null key
map.put("Some Key", null); //Null value
3. Difference Between HashMap and IdentityHashMap
3.1 Reference Equality
IdentityHashMap uses reference equality (==) over the Map’s equals() method when comparing keys (and values). Let us understand with an example.
// Two similar keys but different instances in memory
Integer key1 = new Integer(10);
Integer key2 = new Integer(10);
// Same keys in IdentityHashMap
IdentityHashMap<Integer, String> identityHashMap = new IdentityHashMap<>();
identityHashMap.put(key1, "India");
identityHashMap.put(key2, "USA");
System.out.println("Identity HashMap : " + identityHashMap);
// Same keys in HashMap
HashMap<Integer, String> hashMap = new HashMap<>();
hashMap.put(key1, "India");
hashMap.put(key2, "USA");
System.out.println("HashMap : " + hashMap);
Notice the program output. HashMap rejected the second key because it compares the keys using equals() method and for both keys, the value is 10. IdentityHashMap uses reference equality, and both keys are stored separately in memory so their reference will be unequal.
When we put the key-value pair in HashMap, it updates the previous entry and we get a single entry stored in the Map.
Identity HashMap : {10=USA, 10=India}
HashMap : {10=USA}
3.2 Mutable Keys
We can use Mutable keys in IdentityHashMap whereas for HashMap it is always recommended to use immutable keys.
Let’s understand with an example and create a mutable class ‘Vehicle’. Define the necessary accessor methods, hashCode() and equals() methods.
class Vehicle {
private String name;
private int year;
public Vehicle(String name, int year) {
this.name = name;
this.year = year;
}
//Getters and Setters
@Override
public String toString() {
return "Vehicle{" +
"vehicleName='" + name + '\'' +
", modelYear=" + year +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Vehicle vehicle = (Vehicle) o;
if (Objects.equals(year, vehicle.year)) return false;
return Objects.equals(name, vehicle.name);
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + year;
return result;
}
}
We will add a few key-value pairs to the map and then change the key’s and value’s states. Then we will fetch the entry using the changed key, which should return the original value.
Vehicle vehicle = new Vehicle("Honda", 2015);
Map<Vehicle, String> identityHashMap1 = new IdentityHashMap<>();
identityHashMap1.put(vehicle, "Old Vehicle");
// Changing key state
vehicle.setName("Modified Vehicle");
vehicle.setYear(2022);
// Getting value for key vehicle from the map
System.out.println( identityHashMap1.get(vehicle) ); //Prints 'Modified Vehicle'
4. IdentityHashMap Usecases
IdentityHashMap is used in rare usecases, and we must be careful while using this class.
It helps build specific frameworks, including:
- Spring beans or Singleton types as they manage precisely one instance of certain types
- Maintaining proxy objects for a set of mutable objects
- Class Objects as they are also comparable by reference.
- Cached instances based on an object reference
- Keeping an in-memory graph of objects with reference
5. Conclusion
We learned about IdentityHashMap in Java, its internal workings and how it differs from HashMap. We have also covered practical examples involving both HashMap & IdentityHashMap and how they behave differently w.r.t keys comparison.
Happy Learning !!