Java IdentityHashMap Class and Its Use Cases – Java IdentityHashMap类和它的使用案例

最后修改: 2022年 1月 22日

1. Overview


In this tutorial, we’ll learn how to use the IdentityHashMap class in Java. We’ll also examine how it differs from the general HashMap class. Though this class implements the Map interface, it violates the contract of the Map interface.


For more detailed documentation, we can refer to the IdenityHashMap java doc page. For more details on the general HashMap class, we can read A Guide to Java HashMap.

对于更详细的文档,我们可以参考IdenityHashMap java doc页面。关于一般HashMap类的更多细节,我们可以阅读A Guide to Java HashMap

2. About the IdentityHashMap Class


This class implements the Map interface. The Map interface mandates the use of the equals() method on the key comparison. However, the IdentityHashMap class violates that contract. Instead, it uses reference equality (==) on key search operations.

该类实现了Map接口。Map接口强制要求在键的比较上使用 equals()方法。然而,IdentityHashMap 类违反了该契约。相反,它在键搜索操作上使用了引用相等(==)

During search operations, HashMap uses the hashCode() method for hashing, whereas IdentityHashMap uses the System.identityHashCode() method. It also uses the linear probe technique of the hashtable for search operations.


The use of reference equality, System.identityHashCode(), and the linear probe technique give the IdentityHashMap class a better performance.


3. Using the IdentityHashMap Class


Object construction and method signatures are the same as HashMap, but the behavior is different due to reference equality.


3.1. Creating IdentityHashMap Objects


We can create it using the default constructor:


IdentityHashMap<String, String> identityHashMap = new IdentityHashMap<>();

Or it can be created using the initial expected capacity:


IdentityHashMap<Book, String> identityHashMap = new IdentityHashMap<>(10);

If we don’t specify the initial expectedCapcity parameter as we did above, it uses 21 as the default capacity.


We can also create it using another map object:


IdentityHashMap<String, String> identityHashMap = new IdentityHashMap<>(otherMap);

In this case, it initializes the created identityHashMap with the entries of otherMap.


3.2. Add, Retrieve, Update and Remove Entries


The put() method is used to add an entry:


identityHashMap.put("title", "Harry Potter and the Goblet of Fire");
identityHashMap.put("author", "J. K. Rowling");
identityHashMap.put("language", "English");
identityHashMap.put("genre", "Fantasy");

We can also add all of the entries from the other map using the putAll() method:



To retrieve values, we use the get() method:


String value = identityHashMap.get(key);

To update a value for a key, we use the put() method:


String oldTitle = identityHashMap.put("title", "Harry Potter and the Deathly Hallows");
assertEquals("Harry Potter and the Goblet of Fire", oldTitle);

In the above snippet, the put() method returns the old value after the update. The second statement ensures that oldTitle matches the earlier “title” value.

在上面的片段中,put()方法返回更新后的旧值。第二条语句确保oldTitle与早期的 “title “值相匹配。

We can use the remove() method to remove an element:

我们可以使用 remove()方法来删除一个元素。


3.3. Iterate Through All Entries


We can iterate through all the entries using the entitySet() method:


Set<Map.Entry<String, String>> entries = identityHashMap.entrySet();
for (Map.Entry<String, String> entry: entries) {
    System.out.println(entry.getKey() + ": " + entry.getValue());

We can also iterate through all the entries using the keySet() method:


for (String key: identityHashMap.keySet()) {
    System.out.println(key + ": " + identityHashMap.get(key));

These iterators use a fail-fast mechanism. If the map is modified while iterating, it throws a ConcurrentModificationException.


3.4. Other Methods


We also have different methods available that work similarly to other Map objects:


  • clear(): removes all entries
  • containsKey(): finds whether a key exists in the map or not. Only references are equated
  • containsValue(): finds whether the value exists in the map. Only references are equated
  • keySet(): returns an identity-based keyset
  • size(): returns the number of entries
  • values(): returns a collection of values

3.5. Support for Null Keys and Null Values


IdentityHashMap allows null for both the key and value:


IdentityHashMap<String, String> identityHashMap = new IdentityHashMap<>();
identityHashMap.put(null, "Null Key Accepted");
identityHashMap.put("Null Value Accepted", null);
assertEquals("Null Key Accepted", identityHashMap.get(null));
assertEquals(null, identityHashMap.get("Null Value Accepted"));

The above snippet ensures null both as key and value.


3.6. Concurrency With IdentityHashMap


IdentityHashMap isn’t threadsafe, the same as HashMap. So if we have multiple threads to access/modify IdentityHashMap entries in parallel, we should convert them to the synchronized map.


We can get a synchronized map using the Collections class:


Map<String, String> synchronizedMap = Collections.synchronizedMap(new IdentityHashMap<String, String>());

4. Example Usage of Reference Equality


IdentityHashMap uses reference equality (==) over the equals() method to search/store/access key objects.


An IdentityHashMap created with four properties:


IdentityHashMap<String, String> identityHashMap = new IdentityHashMap<>();
identityHashMap.put("title", "Harry Potter and the Goblet of Fire");
identityHashMap.put("author", "J. K. Rowling");
identityHashMap.put("language", "English");
identityHashMap.put("genre", "Fantasy");

Another HashMap created with the same properties:


HashMap<String, String> hashMap = new HashMap<>(identityHashMap);
hashMap.put(new String("genre"), "Drama");
assertEquals(4, hashMap.size());

When using a new string object genre” as a key, HashMap equates it with the existing key and updates the value. Hence, the size of the hash map remains the same as 4.

当使用一个新的字符串对象genre “作为键时,HashMap将其等同于现有的键并更新其值。因此,哈希图的大小与4保持一致。

The following code snippet shows how IdentityHashMap behaves different:


identityHashMap.put(new String("genre"), "Drama");
assertEquals(5, identityHashMap.size());

IdentityHashMap considers the new “genre” string object as a new key. Hence, it asserts size to be 5. Two different objects of “genre” are used as two keys, with Drama and Fantasy as values.

IdentityHashMap认为新的 “genre “字符串对象是一个新键。因此,它断定大小为5。两个不同的 “genre “对象被用作两个键,DramaFantasy作为值。

5. Mutable Keys


IdentityHashMap allows mutable keys. This is yet another useful feature of this class.


Here we’ll take a simple Book class as a mutable object:


class Book {
    String title;
    int year;
    // other methods including equals, hashCode and toString

First, two mutable objects of Book class are created:


Book book1 = new Book("A Passage to India", 1924);
Book book2 = new Book("Invisible Man", 1953);

Following code shows mutable key usage with HashMap:


HashMap<Book, String> hashMap = new HashMap<>(10);
hashMap.put(book1, "A great work of fiction");
hashMap.put(book2, "won the US National Book Award");
book2.year = 1952;
assertEquals(null, hashMap.get(book2));

Though the book2 entry is present in HashMap, it couldn’t retrieve its value. Because it has been modified and equals() method now doesn’t equate with the modified object. This is why general Map objects mandate immutable objects as a key.


The below snippet uses the same mutable keys with IdentityHashMap:


IdentityHashMap<Book, String> identityHashMap = new IdentityHashMap<>(10);
identityHashMap.put(book1, "A great work of fiction");
identityHashMap.put(book2, "won the US National Book Award");
book2.year = 1951;
assertEquals("won the US National Book Award", identityHashMap.get(book2));

Interestingly, IdentityHashMap is able to retrieve values even when the key object has been modified. In the above code, assertEquals ensures that the same text is retrieved again. This is possible due to reference equality.


6. Some Use Cases


As a result of its features, IdentiyHashMap stands apart from other Map objects. However, it isn’t used for general purposes, and therefore we need to be cautious while using this class.


It’s helpful in building specific frameworks, including:


  • Maintaining proxy objects for a set of mutable objects
  • Building a quick cache based on an object reference
  • Keeping an in-memory graph of objects with references

7. Conclusion


In this article, we learned how to work with IdentityHashMap, how it differs from general HashMap, and some use cases.


A complete code sample can be found over on GitHub.