1. Overview
1.概述
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.
在本教程中,我们将学习如何在Java中使用IdentityHashMap类。我们还将研究它与一般的HashMap类有什么不同。尽管这个类实现了Map接口,但它违反了Map接口的契约。
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
2.关于IdentityHashMap类
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.
在搜索操作中,HashMap使用hashCode()方法进行散列,而IdentityHashMap使用System.identHashCode()方法。它还使用hashtable的线性探测技术进行搜索操作。
The use of reference equality, System.identityHashCode(), and the linear probe technique give the IdentityHashMap class a better performance.
引用平等、System.identityHashCode()和线性探测技术的使用使IdentityHashMap类有更好的性能。
3. Using the IdentityHashMap Class
3.使用IdentityHashMap类
Object construction and method signatures are the same as HashMap, but the behavior is different due to reference equality.
对象构造和方法签名与HashMap相同,但由于引用相等,行为也不同。
3.1. Creating IdentityHashMap Objects
3.1.创建IdentityHashMap对象
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.
如果我们没有像上面那样指定初始expectedCapcity参数,它就会使用21作为默认容量。
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.
在这种情况下,它用otherMap的条目初始化创建的identityHashMap。
3.2. Add, Retrieve, Update and Remove Entries
3.2.添加、检索、更新和删除条目
The put() method is used to add an entry:
put()方法被用来添加一个条目。
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:
我们也可以使用putAll()方法添加其他地图的所有条目。
identityHashMap.putAll(otherMap);
To retrieve values, we use the get() method:
为了检索数值,我们使用get()方法。
String value = identityHashMap.get(key);
To update a value for a key, we use the put() method:
为了更新一个键的值,我们使用put()方法。
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()方法来删除一个元素。
identityHashMap.remove("title");
3.3. Iterate Through All Entries
3.3.遍历所有条目
We can iterate through all the entries using the entitySet() method:
我们可以使用entitySet()方法遍历所有条目。
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:
我们还可以使用keySet()方法遍历所有条目。
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.
这些迭代器使用fail-fast机制。如果地图在迭代时被修改,它会抛出一个ConcurrentModificationException。
3.4. Other Methods
3.4.其他方法
We also have different methods available that work similarly to other Map objects:
我们也有不同的方法可用,其作用与其他Map对象类似。
- 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
3.5.支持Null键和Null值
IdentityHashMap allows null for both the key and value:
IdentityHashMap允许键和值都为null。
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.
上述片段确保null既是键也是值。
3.6. Concurrency With IdentityHashMap
3.6.使用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.
IdentityHashMap不是线程安全的,与HashMap相同。因此,如果我们有多个线程并行地访问/修改IdentityHashMap条目,我们应该将它们转换为同步地图。
We can get a synchronized map using the Collections class:
我们可以使用Collections类得到一个同步的地图。
Map<String, String> synchronizedMap = Collections.synchronizedMap(new IdentityHashMap<String, String>());
4. Example Usage of Reference Equality
4.参考文献平等的使用实例
IdentityHashMap uses reference equality (==) over the equals() method to search/store/access key objects.
IdentityHashMap在equals()方法上使用引用相等(==)来搜索/存储/访问键对象。
An IdentityHashMap created with four properties:
一个带有四个属性的IdentityHashMap创建。
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。
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的不同行为。
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 “对象被用作两个键,“Drama“和“Fantasy“作为值。
5. Mutable Keys
5.可变的钥匙
IdentityHashMap allows mutable keys. This is yet another useful feature of this class.
IdentityHashMap允许可变键。这是该类的另一个有用的特性。
Here we’ll take a simple Book class as a mutable object:
在这里,我们将把一个简单的Book类作为一个可变的对象。
class Book {
String title;
int year;
// other methods including equals, hashCode and toString
}
First, two mutable objects of Book class are created:
首先,创建两个Book类的可变对象。
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的可变键的用法。
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.
尽管book2条目存在于HashMap中,但它无法检索到它的值。因为它已经被修改了,而equals()方法现在并不等同于被修改的对象。这就是为什么一般的Map对象强制要求不可变的对象作为键。
The below snippet uses the same mutable keys with IdentityHashMap:
下面的片段使用了与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.
有趣的是,IdentityHashMap能够检索值,即使键对象已被修改。在上面的代码中,assertEquals确保再次检索到相同的文本。由于引用平等,这是有可能的。
6. Some Use Cases
6.一些使用案例
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.
由于其特性,IdentiyHashMap与其他Map对象不同。然而,它并不用于一般用途,因此我们在使用这个类时需要谨慎。
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
7.结语
In this article, we learned how to work with IdentityHashMap, how it differs from general HashMap, and some use cases.
在这篇文章中,我们学习了如何使用IdentityHashMap,它与一般的HashMap有什么区别,以及一些使用案例。
A complete code sample can be found over on GitHub.
完整的代码样本可以在GitHub上找到over。