在 Java 中,Map 是一个集合框架接口,用于存储键值对(key-value pairs)。每个键在 Map 中是唯一的,可以映射到一个值。Map 接口不直接继承 Collection 接口,但它提供了操作键值对的多种方法。

1. Map 接口的基本概念

  • 键(Key):唯一的标识符,映射到一个值。
  • 值(Value):与键关联的数据。
  • 键值对(Entry):一个 Map 条目由一个键和值组成。

Map 接口有几个常用的实现类,其中最常用的是 HashMapTreeMap

2. Map 接口的方法

Map 接口定义了许多方法,用于添加、移除、查找和修改映射。下面是 Map 接口常用的几个方法:

  • put(K key, V value):将指定的值与指定的键关联。如果该键已经存在,则更新对应的值。
  • get(Object key):根据指定的键返回对应的值。如果键不存在,返回 null
  • remove(Object key):根据指定的键删除对应的键值对。
  • containsKey(Object key):检查是否包含指定的键。
  • containsValue(Object value):检查是否包含指定的值。
  • size():返回 Map 中键值对的数量。
  • clear():移除所有的键值对。
  • keySet():返回所有键的集合。
  • values():返回所有值的集合。
  • entrySet():返回所有键值对的集合。

3. 常见的 Map 实现类

Java 提供了多个 Map 接口的实现类,不同的实现类具有不同的特点,最常用的有:

(1)HashMap

HashMapMap 接口最常用的实现。它基于哈希表实现,允许键和值为 null,并且它不保证键值对的顺序。

import java.util.HashMap;
import java.util.Map;

public class HashMapExample {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
        
        // 添加键值对
        map.put("One", 1);
        map.put("Two", 2);
        map.put("Three", 3);
        
        // 获取值
        System.out.println("Value for 'Two': " + map.get("Two"));
        
        // 检查键是否存在
        System.out.println("Contains 'One': " + map.containsKey("One"));
        
        // 删除键值对
        map.remove("Three");
        
        // 遍历 Map
        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            System.out.println(entry.getKey() + " = " + entry.getValue());
        }
        
        // 打印 Map 的大小
        System.out.println("Size of map: " + map.size());
    }
}

输出

Value for 'Two': 2
Contains 'One': true
One = 1
Two = 2
Size of map: 2

(2)TreeMap

TreeMap 是基于红黑树实现的,它将键按自然顺序(或通过比较器 Comparator)进行排序。TreeMap 不允许键为 null

import java.util.Map;
import java.util.TreeMap;

public class TreeMapExample {
    public static void main(String[] args) {
        Map<String, Integer> map = new TreeMap<>();
        
        map.put("One", 1);
        map.put("Two", 2);
        map.put("Three", 3);
        
        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            System.out.println(entry.getKey() + " = " + entry.getValue());
        }
    }
}

输出

One = 1
Three = 3
Two = 2

TreeMap 根据键的自然顺序或自定义的 Comparator 进行排序。

(3)LinkedHashMap

LinkedHashMapHashMap 的一个变种,它维护了元素插入的顺序,或者可以通过访问顺序(按最近访问的顺序)来遍历键值对。

import java.util.Map;
import java.util.LinkedHashMap;

public class LinkedHashMapExample {
    public static void main(String[] args) {
        Map<String, Integer> map = new LinkedHashMap<>();
        
        map.put("One", 1);
        map.put("Two", 2);
        map.put("Three", 3);
        
        // 按插入顺序遍历
        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            System.out.println(entry.getKey() + " = " + entry.getValue());
        }
    }
}

输出

One = 1
Two = 2
Three = 3

LinkedHashMap 允许根据插入顺序来迭代元素,或者可以设置为按访问顺序进行迭代。

4. 使用 Map 时的常见操作

(1)遍历 Map

  • 使用 for-each 循环遍历键值对:
Map<String, Integer> map = new HashMap<>();
map.put("One", 1);
map.put("Two", 2);
map.put("Three", 3);

for (Map.Entry<String, Integer> entry : map.entrySet()) {
    System.out.println(entry.getKey() + ": " + entry.getValue());
}
  • 使用 keySet() 遍历所有键:
for (String key : map.keySet()) {
    System.out.println(key + ": " + map.get(key));
}
  • 使用 values() 遍历所有值:
for (Integer value : map.values()) {
    System.out.println(value);
}

(2)计算 Map 中某个键对应的值

如果某个键不存在时可以提供默认值:

map.putIfAbsent("Four", 4);  // 如果 "Four" 不存在,才添加
int value = map.getOrDefault("Five", 0);  // 如果 "Five" 不存在,返回 0

(3)合并值

可以使用 merge() 方法来根据已有的值合并新的值:

map.merge("Two", 1, Integer::sum);  // 将 "Two" 键的值加 1

(4)移除条件匹配的键值对

map.remove("Three", 3);  // 只有值为 3 时才会删除 "Three"

5. Map 接口与并发

  • ConcurrentHashMap 是一个线程安全的 Map 实现。它允许多个线程同时访问不同的部分,避免了传统的 HashMap 中的同步问题。
  • HashMap 不是线程安全的,适用于单线程环境或外部同步的环境。

总结

  • Map 接口是 Java 集合框架的一部分,用于存储键值对(key-value pairs)。
  • 常见的实现类有 HashMapTreeMapLinkedHashMap 等。
  • Map 提供了多种方法来操作和管理键值对,如 put()get()remove()size()clear() 等。
  • TreeMap 按照键的自然顺序或指定的比较器进行排序,而 LinkedHashMap 保持插入顺序或访问顺序。

通过合理选择不同的 Map 实现类,可以根据不同的需求(如排序、插入顺序、性能要求等)来优化程序的设计。