Map 接口与实现
Map 是键值对(Key-Value)映射的集合,键唯一,值可重复。
Map 接口特点
| 特性 | 说明 |
|---|---|
| 键唯一 | 每个键只能映射一个值 |
| 值可重复 | 多个键可以映射相同的值 |
| 键可null | HashMap 允许一个 null 键,TreeMap 不允许 |
Map 核心方法
Java
// 添加/更新
map.put(key, value); // 添加或更新键值对
map.putAll(otherMap); // 添加另一个 Map
// 获取
map.get(key); // 获取值,不存在返回 null
map.getOrDefault(key, default); // 获取值,不存在返回默认值
// 删除
map.remove(key); // 删除键值对
map.clear(); // 清空
// 判断
map.containsKey(key); // 是否包含键
map.containsValue(value); // 是否包含值
// 集合视图
map.keySet(); // 所有键的 Set
map.values(); // 所有值的 Collection
map.entrySet(); // 所有键值对的 Set
HashMap
特点
- 基于哈希表(数组+链表/红黑树)实现
- 无序:键顺序不确定
- 查询/插入/删除:O(1)
- 允许一个 null 键和多个 null 值
- JDK 8:链表长度 > 8 且容量 > 64 时转为红黑树
使用示例
Java
Map<String, Integer> map = new HashMap<>();
map.put("张三", 25);
map.put("李四", 30);
map.put("张三", 28); // 更新张三的值
Integer age = map.get("张三"); // 28
Integer age = map.getOrDefault("王五", 0); // 0
// 遍历键
for (String key : map.keySet()) {
System.out.println(key + ":" + map.get(key));
}
// 遍历键值对(推荐)
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + ":" + entry.getValue());
}
// 函数式遍历(Java 8+)
map.forEach((k, v) -> System.out.println(k + ":" + v));
扩容机制:默认容量 16,负载因子 0.75,超过容量 × 负载因子时扩容为 2 倍。
LinkedHashMap
特点
- HashMap 的子类
- 有序:按插入顺序或访问顺序排列
- 维护双向链表记录顺序
- 性能略低于 HashMap
使用示例
Java
// 插入顺序(默认)
Map<String, Integer> map = new LinkedHashMap<>();
map.put("A", 1);
map.put("B", 2);
map.put("C", 3);
System.out.println(map); // {A=1, B=2, C=3}
// 访问顺序(LRU 缓存)
Map<String, Integer> lruMap = new LinkedHashMap<>(16, 0.75f, true);
lruMap.put("A", 1);
lruMap.put("B", 2);
lruMap.get("A"); // 访问 A,A 移到最后
System.out.println(lruMap); // {B=2, A=1}
适用场景:需要保持顺序的键值对存储,或实现简单的 LRU 缓存。
TreeMap
特点
- 基于红黑树实现
- 自然排序:键按自然顺序排列
- 查询/插入/删除:O(log n)
- 不允许 null 键
使用示例
Java
// 自然排序
Map<Integer, String> map = new TreeMap<>();
map.put(3, "C");
map.put(1, "A");
map.put(2, "B");
System.out.println(map); // {1=A, 2=B, 3=C}(排序后)
// 自定义排序
Map<String, Integer> map = new TreeMap<>(Comparator.reverseOrder());
map.put("A", 1);
map.put("B", 2);
System.out.println(map); // {B=2, A=1}
// TreeMap 特有方法
TreeMap<Integer, String> tm = new TreeMap<>();
tm.firstKey(); // 最小键
tm.lastKey(); // 最大键
tm.lowerKey(5); // 小于 5 的最大键
tm.higherKey(5); // 大于 5 的最小键
tm.headMap(5); // 键小于 5 的子 Map
tm.tailMap(5); // 键大于等于 5 的子 Map
HashMap vs LinkedHashMap vs TreeMap
| 特性 | HashMap | LinkedHashMap | TreeMap |
|---|---|---|---|
| 顺序 | 无序 | 插入/访问顺序 | 自然排序 |
| 性能 | O(1)最快 | O(1)略慢 | O(log n) |
| null键 | 允许一个 | 允许一个 | 不允许 |
| 适用场景 | 一般映射 | 有序/LRU缓存 | 排序映射 |
Java 8 新增方法
Java
Map<String, Integer> map = new HashMap<>();
// compute:根据键计算新值
map.compute("张三", (k, v) -> v == null ? 0 : v + 1);
// computeIfAbsent:键不存在时计算并放入
map.computeIfAbsent("李四", k -> 30);
// computeIfPresent:键存在时计算新值
map.computeIfPresent("张三", (k, v) -> v + 1);
// merge:合并值
map.merge("张三", 1, (old, newV) -> old + newV);
// putIfAbsent:键不存在时放入
map.putIfAbsent("王五", 25);
要点总结
- Map:键值对映射,键唯一
- HashMap:无序,性能最高 O(1)
- LinkedHashMap:有序(插入/访问顺序),可实现 LRU 缓存
- TreeMap:自然排序,性能 O(log n)
- 遍历推荐 entrySet() 或 forEach()
- Java 8 新增 compute/merge 等方法简化操作
- 选择原则:一般用 HashMap,有序用 LinkedHashMap,排序用 TreeMap
📝 发现内容有误?点击此处直接编辑