Java Map 接口

2025 年 4 月 1 日 | 阅读 13 分钟

Java Map 接口是一种结构,它包含一组键值对,其中每个键都是唯一的,并且只指向一个值。它是 java.util 包的组成部分,在 Java 编程中被广泛用于以有序的方式组织和获取数据。如果您需要根据键来搜索、更新或删除元素,Map 会非常有用。

为什么需要 Java Map 接口?

以下是一些您可能会发现使用 `Map` 接口有益的情况和原因:

高效的数据检索: Map 使用键来选择性地读取值。如果您需要将一组数据与另一组数据关联起来,以便能够通过键输入来查找相关信息,那么 Map 会很好地满足您的需求。例如,当您拥有大量数据集并希望快速搜索与特定键(如 ID、姓名或代码)对应的任何内容时,Map 可以提供对这些数据的快速访问。

无重复键: Map 的键是唯一的,因此一个特定的键必须是唯一的。当目标是确保每个键只表示一个值时,此功能非常方便。此外,在字典应用程序中,您需要确保每个单词只有一个定义。

键和值类型的灵活性: Java Map 具有存储多种类型键和值的能力。您可以使用任何实现了 hashCode() 和 equals() 方法的对象作为键,并使用任何对象作为值。它为您提供了可视化对象之间不同关系的选项。

关联数据结构: Map 常用于关联数组、字典和符号表。它为存储和检索信息提供了方便的空间,每个项目都有其特定的索引。

缓存和记忆化: Map 在缓存和记忆化方面非常有用。您可以将昂贵操作的结果或特定操作的结果保存在 Map 中,并将它们与操作的输入或参数绑定。这使您能够在再次出现相同输入时直接访问存储在 Map 中的项,而无需从头开始重新计算。

Java Map Hierarchy

Map 不允许重复键,但允许重复值。HashMap 和 LinkedHashMap 允许 null 键和值,但 TreeMap 不允许任何 null 键或值。

Map 不能直接遍历,因此需要使用 `keySet()` 或 `entrySet()` 方法将其转换为 Set。

Class描述
HashMapHashMap 是 Map 的一种实现,但它不维护任何顺序。
LinkedHashMapLinkedHashMap 是 Map 的一种实现。它继承了 HashMap 类。它维护插入顺序。
TreeMapTreeMap 是 Map 和 SortedMap 的一种实现。它维护升序。

Map 接口的常用方法

方法描述
V put(Object key, Object value)用于将一个条目插入 Map 中。
void putAll(Map map)用于将指定的 Map 插入到当前 Map 中。
V putIfAbsent(K key, V value)仅当 Map 中尚未指定与指定键关联的值时,才将指定的键值对插入 Map 中。
V remove(Object key)用于删除指定键的条目。
boolean remove(Object key, Object value)用于从 Map 中删除与指定键关联的指定值。
Set keySet()返回包含所有键的 Set 视图。
Set<Map.Entry<K,V>> entrySet()返回包含所有键值对的 Set 视图。
void clear()用于重置 Map。
V compute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)用于计算指定键及其当前映射值(如果不存在则为 null)的映射,并更新 Map。
V computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction)如果指定的键尚未与值关联(或映射为 null),则使用给定的映射函数计算其值,并将其输入到此 Map 中,除非结果为 null。
V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)如果指定键的值存在且非 null,则用于计算给定键及其当前映射值的新映射。
boolean containsValue(Object value)如果 Map 中存在与指定值相等的某个值,则返回 true,否则返回 false。
boolean containsKey(Object key)如果 Map 中存在与指定键相等的某个键,则返回 true,否则返回 false。
boolean equals(Object o)用于将指定的对象与 Map 进行比较。
void forEach(BiConsumer<? super K,? super V> action)对 Map 中的每个条目执行给定的操作,直到所有条目都被处理完毕或操作抛出异常。
V get(Object key)返回与键关联的值的对象。
V getOrDefault(Object key, V defaultValue)返回指定键映射到的值,如果 Map 中没有该键的映射,则返回 defaultValue。
int hashCode()返回 Map 的哈希码值。
boolean isEmpty()如果 Map 为空,则返回 true;如果 Map 包含至少一个键,则返回 false。
V merge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction)如果指定的键尚未与值关联或与 null 关联,则将其与给定的非 null 值关联。
V replace(K key, V value)替换指定键的指定值。
boolean replace(K key, V oldValue, V newValue)为指定键替换旧值与新值。
void replaceAll(BiFunction<? super K,? super V,? extends V> function)通过调用给定的函数来替换每个条目的值,直到所有条目都被处理完毕或函数抛出异常。
集合values()返回 Map 中包含的值的 collection 视图。
int size()返回 Map 中条目的数量。

Map.Entry 接口

Map.Entry 是 Map 接口的一个内部接口,代表 Map 中的单个键值对。它还可以允许获取 Map 并遍历其条目、将 Map 转换为键/值的集合等。它返回 Map 的 collection 视图,其中的元素是此类的实例。它提供了获取键和值的方法。

Map.Entry 接口的方法

方法描述
K getKey()用于获取键。
V getValue()用于获取值。
int hashCode()用于获取哈希码。
V setValue(V value)用于将此条目对应的值替换为指定的值。
boolean equals(Object o)用于将指定的对象与现有对象进行比较。
static <K extends Comparable<? super K>,V> Comparator<Map.Entry<K,V>> comparingByKey()返回一个比较器,用于按键的自然顺序比较对象。
static <K,V> Comparator<Map.Entry<K,V>> comparingByKey(Comparator<? super K> cmp)返回一个比较器,使用给定的比较器按键比较对象。
static <K,V extends Comparable<? super V>> Comparator<Map.Entry<K,V>> comparingByValue()返回一个比较器,用于按值的自然顺序比较对象。
static <K,V> Comparator<Map.Entry<K,V>> comparingByValue(Comparator<? super V> cmp)返回一个比较器,使用给定的比较器按值比较对象。

Java Map 示例:非泛型(旧样式)

示例

输出

1 Amit
2 Jai
5 Rahul
6 Amit

示例

编译并运行

输出

100 Amit
101 Vijay
102 Rahul

Java Map 示例:comparingByKey()

示例

编译并运行

输出

100=Amit
101=Vijay
102=Rahul

Java Map 示例:comparingByKey() 降序

示例

编译并运行

输出

102=Rahul
101=Vijay
100=Amit

Map 接口由几个类实现。一些常用且实现 Map 接口的类包括:

HashMap

HashMap 是 Java 中一种重要的数据结构,它实现了 Map 接口。因此,它提供了一种存储键值对的方案。HashMap 中的每个键都是唯一的,每个键只有一个值。这使得可以通过与之配对的键来查找值。

HashMap 最重要的特性之一是其底层实现为哈希表,这使得基本操作(如插入、删除和检索)在平均情况下具有恒定的时间性能,前提是有一个好的哈希函数和适当的容量管理。

示例

示例

编译并运行

输出

Student with ID 1002 is: Emily BrownStudent Records:
ID: 1001, Name: John Smith
ID: 1002, Name: Emily Brown
ID: 1003, Name: Michael Johnson
Student with ID 1004 exists in records: false

LinkedHashMap

LinkedHashMap 是 Java 中的一个类,它扩展了 HashMap 并实现了 Map 接口。它在功能上类似于 HashMap,但维护可预测的迭代顺序,即键插入 Map 的顺序(插入顺序)。这使得 LinkedHashMap 成为需要保留插入顺序的场景的理想选择。

LinkedHashMap 的一个特殊功能是它维护一个双向链表来存储其条目,这使得您可以按插入顺序或访问顺序(最后访问条目的顺序)遍历条目。

示例

示例

编译并运行

输出

Student Records:
ID: 1001, Name: John Smith
ID: 1002, Name: Emily Brown
ID: 1003, Name: Michael Johnson

TreeHashMap

Java 中的 TreeMap 是一个有序 Map 实现,它将键值对存储在红黑树结构中。它保证元素根据其键进行排序,无论是自然排序还是用户定义的比较器。这种数据结构为插入、删除和检索操作提供了 O(log n) 的时间效率。TreeMap 实现 NavigableMap 接口,提供导航和基于范围的操作方法。一些使用示例包括按排序顺序维护字典、实现范围搜索和按排序顺序运行数据。

示例

示例

编译并运行

输出

Student Records:
ID: 1001, Name: John Smith
ID: 1002, Name: Emily Brown
ID: 1003, Name: Michael Johnson

Map 接口的优点

键值对: Map 接口允许您以键值对的形式存储数据,其中每个键在 Map 中都是唯一的。这种配对可以从键中快速检索数据。

快速数据检索: Map 允许根据键快速查找值。元素的检索、插入和删除在时间效率上是高效的,这取决于实现和具体操作(如 HashMap 或 TreeMap),平均时间复杂度为 O(1) 或 O(log n),同样取决于实现。

高效的数据组织: Map 是组织和存储数据的有效工具。内部实现,如哈希表(在 HashMap 中)或平衡树(在 TreeMap 中),保证数据以最优方式布局,以实现快速检索和修改。

键类型的灵活性: Map 接口允许键是任何实现了 hashCode() 和 equals() 方法的对象。因此,您可以使用自定义对象作为键,从而实现更复杂的结构和映射。

遍历条目的能力: Map 提供遍历其条目的方法,使您能够同时操作键和值。这允许执行诸如遍历所有键值对的循环、计算或根据特定条件过滤条目等操作。

支持 null 值: 根据实现,Map 可以支持 null 值,从而可以在 Map 中存储和检索 null 作为有效值。当 null 表示有效值或缺失值时,这可能适用于用例。

动态大小: Map 可以根据添加或删除的项动态调整其大小。它通过避免过度的内存开销和性能下降,确保 Map 有效地处理不同数量的数据。

广泛的实现: Java 有 Map 接口的不同实现(如 HashMap、LinkedHashMap、TreeMap),它们在质量和性能特性上有所不同。这使您可以选择满足您特定需求的实现,例如速度、内存消耗或迭代顺序。

Map 接口的缺点

性能可变性: 实现(例如,HashMap、TreeMap)会影响 Map 操作(例如,插入、检索、删除)的性能特性。例如,HashMap 的特点是基本操作的平均时间复杂度为恒定时间。但是,由于哈希冲突,在最坏情况下它可能会达到线性时间。

内存开销: Map 比其他数据结构使用更多的内存,因为它们需要存储键和值。此外,一些 Map 实现(例如,TreeMap)可能需要更多内存来维护通常是平衡树的数据结构。

顺序: 一些 Map 实现(例如,HashMap)不维护元素的任何排序顺序,当您需要按特定顺序遍历元素时,这可能是一个缺点。与 LinkedHashMap 不同,TreeMap 根据其键对数据元素进行排序,这可能并不总是符合所需的顺序。

键约束: Map 接口对键施加限制,要求它们在 Map 中是唯一的,并实现相应的 equals() 和 hashCode() 方法。当处理自定义键类型或键不支持这些方法时,这种可寻址性会受到限制。

同步开销: 许多 Map 实现默认不是线程安全的;因此,当多个线程同时访问时,它们可能导致并发问题。一个选项是使用外部同步机制来同步 Map。然而,这可能会带来性能开销,并可能导致竞态条件和死锁。

迭代开销: 遍历 Map 的元素会产生开销,尤其是对于大型 Map,因为必须遍历所有元素。在某些 Map 实现(例如,HashMap、LinkedHashMap)中可以进行迭代,但由于其树结构,TreeMap 在迭代成本方面可能更昂贵。


Java Map 选择题

1. 哪个类不实现 Map 接口?

  1. HashMap
  2. TreeMap
  3. LinkedHashMap
  4. ArrayList
 

答案:D

解释: ArrayList 是实现 List 接口的类,而不是 Map 接口。其他类(HashMap、TreeMap 和 LinkedHashMap)都实现了 Map 接口。


2. 通过键访问 HashMap 中的值的复杂度是多少?

  1. O(1)
  2. O(log n)
  3. O(n)
  4. O(n log n)
 

答案:A

解释: 在 HashMap 中,通过键访问值通常具有 O(1) 的时间复杂度,假设有一个好的哈希函数和低的哈希冲突。


3. 哪个 Map 实现维护插入顺序?

  1. HashMap
  2. TreeMap
  3. LinkedHashMap
  4. Hashtable
 

答案:C

解释: LinkedHashMap 根据其插入顺序维护元素的顺序,而 HashMap 和 Hashtable 则不维护。


4. TreeMap 如何存储其元素?

  1. 插入顺序
  2. 基于哈希值
  3. 根据自然顺序或比较器排序
  4. 无特定顺序
 

答案:C

解释: TreeMap 根据其自然顺序或在创建 Map 时提供的比较器对元素进行排序。


5. 使用哪个方法从 Map 中检索与给定键关联的值?

  1. getValue()
  2. getKey()
  3. get()
  4. find()
 

答案:C

解释: `get()` 方法用于检索 Map 中与指定键关联的值。


下一个主题Java HashMap 类