源本科技 | 码上会

Java Map

2026/01/28
43
0

学习目标

  • 理解 Map 接口的核心概念:键值对映射键的唯一性

  • 掌握主流 Map 实现类(HashMapLinkedHashMapTreeMapHashtable)的特性与适用场景

  • 熟练进行 Map 的增、删、改、查及遍历操作

  • 能够在多线程环境中安全使用 Map


什么是 Map

Map 是 Java 集合框架中的核心接口之一,位于 java.util 包中。它表示一组(Key),其中:

  • 键必须唯一(不能重复)

  • 值可以重复

  • 提供基于键的高效查找、插入和删除操作

注意:Map 不是 Collection 的子接口,因此不继承 Collection 的方法。

泛型声明

public interface Map<K, V>
  • K:键的类型

  • V:值的类型


Map 的继承体系


Map 实现类

实现类

底层结构

是否有序

是否允许 null

线程安全

特点

HashMap

哈希表 + 链表 / 红黑树(Java 8+)

❌ 无序

✅ 允许一个 null 键和多个 null 值

性能最优,通用首选

LinkedHashMap

哈希表 + 双向链表

✅ 按插入顺序(或访问顺序)

✅ 同 HashMap

保持插入 / 访问顺序

TreeMap

红黑树

✅ 按键的自然顺序或自定义比较器

❌(自然排序时)

自动排序,支持范围查询

Hashtable

哈希表

❌ 无序

❌ 不允许 null

老旧同步实现,性能差

ConcurrentHashMap

分段锁 / CAS(Java 8+)

❌ 无序

高并发安全,推荐替代 Hashtable

最佳实践

  • 单线程 → HashMap

  • 需要顺序 → LinkedHashMap

  • 需要排序 → TreeMap

  • 多线程 → ConcurrentHashMap


创建 Map

由于 Map 是接口,必须通过实现类实例化:

// 推荐写法(Java 7+ 钻石操作符)
Map<String, Integer> map = new HashMap<>();

// 其他实现
Map<String, String> linkedMap = new LinkedHashMap<>();
Map<Integer, String> treeMap = new TreeMap<>();

常见操作

1. 添加元素

使用 put(K key, V value) 方法:

Map<String, Integer> m = new HashMap<>();
m.put("Alice", 25);
m.put("Bob", 30);
m.put("Alice", 26); // 更新已有键

System.out.println(m); // {Alice=26, Bob=30}(顺序不定)

注意:重复的键会覆盖旧值。

安全添加(仅当键不存在时)

m.putIfAbsent("Charlie", 35); // 仅当 "Charlie" 不存在时才添加

2. 修改元素

直接使用 put() 即可更新:

m.put("Bob", 31);
System.out.println(m); // {Alice=26, Bob=31}

3. 删除元素

m.remove("Alice"); // 删除键为 "Alice" 的条目
System.out.println(m); // {Bob=31}

4. 遍历元素

entrySet()(推荐)

for (Map.Entry<String, Integer> entry : m.entrySet()) {
    System.out.println(entry.getKey() + " : " + entry.getValue());
}

keySet()

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

values()

for (Integer value : m.values()) {
    System.out.println(value);
}

性能建议:优先使用 entrySet(),避免多次调用 get()


常用方法

方法

描述

put(K, V)

添加或更新键值对

putIfAbsent(K, V)

仅当键不存在时添加

get(Object key)

获取键对应的值(不存在返回 null

getOrDefault(K, V)

获取值,若不存在则返回默认值

remove(Object key)

删除指定键的映射

containsKey(Object key)

判断是否包含某键

containsValue(Object value)

判断是否包含某值

size()

返回键值对数量

isEmpty()

判断是否为空

clear()

清空所有映射

keySet()

返回所有键的 Set 视图

values()

返回所有值的 Collection 视图

entrySet()

返回所有键值对的 Set<Map.Entry> 视图

putAll(Map<? extends K, ? extends V> m)

批量添加另一个 Map 的所有映射


特殊功能

getOrDefault

避免空指针

Map<String, Integer> scores = new HashMap<>();
int aliceScore = scores.getOrDefault("Alice", 0); // 若无 "Alice",返回 0

merge

合并值

// 统计词频
Map<String, Integer> wordCount = new HashMap<>();
wordCount.merge("Java", 1, Integer::sum); // 若存在则累加,否则设为 1

线程安全处理

ConcurrentHashMap

ConcurrentHashMap<String, Integer> concurrentMap = new ConcurrentHashMap<>();
concurrentMap.put("key", 1);
Integer value = concurrentMap.get("key");
  • 高并发性能优异

  • 支持原子操作(如 computeIfAbsent


重点总结

  • Map 存储键值对键唯一,值可重复

  • HashMap 是默认选择;LinkedHashMap 保持顺序;TreeMap 自动排序

  • 遍历时优先使用 entrySet() 提升性能

  • 多线程环境下应使用 ConcurrentHashMap,而非 HashtablesynchronizedMap

  • 利用 getOrDefaultputIfAbsentmerge 等现代方法编写更安全、简洁的代码


思考题

  1. 为什么 TreeMap 在使用自然排序时不允许 null 键?这与其底层红黑树结构有什么关系?

  2. 在实现一个缓存系统时,如果希望最近访问的元素排在最后(LRU 缓存),应选择哪种 Map?如何配置?

  3. HashMap 在 Java 8 中引入了“链表转红黑树”的优化,这一机制在什么条件下触发?有何好处?