Guide to Java IdentityHashMap

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 Collectionsthe 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.

IdentityHashMap

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): returns true or false 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 !!

Source Code on Github

Leave a Reply

0 Comments
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions, and frequently asked interview questions.