本教程适用于JDK 8。本页面中描述的示例和实践不利用后续版本中引入的改进,并可能使用不再可用的技术。
有关Java SE 9和后续版本中更新的语言特性的摘要,请参阅Java语言变更。
有关所有JDK版本的新功能、增强功能以及已删除或已弃用选项的信息,请参阅JDK发布说明。
Map
实现分为通用型、特殊型和并发型实现。
通用型的Map
实现有HashMap
、TreeMap
和LinkedHashMap
。如果你需要SortedMap
操作或按键排序的Collection
遍历,使用TreeMap
;如果你想要最大速度且不关心遍历顺序,使用HashMap
;如果你想要接近HashMap
性能且按插入顺序遍历,使用LinkedHashMap
。在这方面,Map
的情况类似于Set
。同样,Set实现部分中的其他内容也适用于Map
实现。
LinkedHashMap
提供了两个LinkedHashSet
不具备的功能。当你创建一个LinkedHashMap
时,你可以基于键的访问顺序来排序它,而不是插入顺序。换句话说,仅仅查找与键关联的值会将该键移动到映射的末尾。此外,LinkedHashMap
提供了removeEldestEntry
方法,可以重写该方法以在向映射添加新的映射时自动删除过时的映射。这使得实现自定义缓存非常容易。
例如,下面的重写将允许该映射增长到最多100个条目,然后每次添加新条目时,它将删除最老的条目,以维持100个条目的稳态。
private static final int MAX_ENTRIES = 100; protected boolean removeEldestEntry(Map.Entry eldest) { return size() > MAX_ENTRIES; }
特殊型的Map
实现有EnumMap
、WeakHashMap
和IdentityHashMap
。以array
内部实现的EnumMap
是一种高性能的用于枚举键的Map
实现。该实现结合了Map
接口的丰富性和安全性,速度接近数组。如果你想将枚举映射到一个值,应优先使用EnumMap
而不是数组。
WeakHashMap
是实现了Map
接口的类,它只存储对其键的弱引用。仅存储弱引用使得当键不再在WeakHashMap
外部引用时,可以对键值对进行垃圾回收。这个类提供了利用弱引用的最简单方式。它对于实现"注册表"类似的数据结构非常有用,在这种数据结构中,当键不再被任何线程引用时,条目的实用性消失。
IdentityHashMap
是一个基于标识的Map
实现,它基于哈希表。这个类对于保持拓扑结构的对象图转换非常有用,比如序列化或深拷贝。为了执行这样的转换,你需要维护一个基于标识的"节点表",用于跟踪已经被访问过的对象。基于标识的映射也用于在动态调试器和类似系统中维护对象到元信息的映射。最后,基于标识的映射在阻止由于故意反常的equals
方法而导致的"欺骗攻击"方面也非常有用,因为IdentityHashMap
不会调用其键的equals
方法。这个实现的一个附加好处是它很快。
java.util.concurrent
包包含了扩展了Map
的原子putIfAbsent
、remove
和replace
方法的ConcurrentMap
接口,以及该接口的实现ConcurrentHashMap
。
ConcurrentHashMap
是一个高度并发、高性能的基于哈希表的实现。这个实现在执行检索操作时不会阻塞,并允许客户端选择并发级别进行更新。它被设计成Hashtable
的一个即插即用替代品:除了实现ConcurrentMap
接口,它还支持所有与Hashtable
特有的遗留方法。同样,如果你不需要遗留操作,要小心使用ConcurrentMap
接口操作它。