Map与HashMap
Map是键值对集合,本课学习Map的使用。
Map接口特点
| 特点 | 说明 |
|---|---|
| 键值对 | 每个元素包含键和值 |
| 键不重复 | 键唯一,值可重复 |
| 无序 | HashMap无序 |
HashMap
HashMap是最常用的Map实现。
创建HashMap
JAVA
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> map1 = new HashMap<>();
Map<String, Integer> map2 = new HashMap<>(100); // 指定容量
Map<String, Integer> map3 = new HashMap<>(map1); // 从其他Map创建
基本操作
JAVA
import java.util.HashMap;
import java.util.Map;
public class HashMapDemo {
public static void main(String[] args) {
Map<String, Integer> scores = new HashMap<>();
// 添加键值对
scores.put("Alice", 95);
scores.put("Bob", 88);
scores.put("Charlie", 92);
System.out.println("Map:" + scores);
// 获取值
int aliceScore = scores.get("Alice");
System.out.println("Alice的分数:" + aliceScore);
// 获取值(键不存在返回默认值)
int davidScore = scores.getOrDefault("David", 0);
System.out.println("David的分数:" + davidScore);
// 判断
System.out.println("是否包含Alice:" + scores.containsKey("Alice"));
System.out.println("是否包含95:" + scores.containsValue(95));
System.out.println("大小:" + scores.size());
// 修改
scores.put("Alice", 98); // 覆盖旧值
System.out.println("修改后Alice:" + scores.get("Alice"));
// 删除
scores.remove("Bob");
System.out.println("删除后:" + scores);
}
}
putIfAbsent
JAVA
Map<String, Integer> map = new HashMap<>();
map.put("Alice", 95);
// 只有键不存在时才添加
map.putIfAbsent("Alice", 100); // 不会覆盖
map.putIfAbsent("Bob", 88); // 会添加
System.out.println(map); // {Alice=95, Bob=88}
遍历方式
方式1:遍历keySet
JAVA
Map<String, Integer> map = new HashMap<>();
map.put("Alice", 95);
map.put("Bob", 88);
map.put("Charlie", 92);
for (String key : map.keySet()) {
System.out.println(key + ": " + map.get(key));
}
方式2:遍历values
JAVA
for (int value : map.values()) {
System.out.println(value);
}
方式3:遍历entrySet
JAVA
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
方式4:Lambda
JAVA
map.forEach((key, value) -> System.out.println(key + ": " + value));
示例:Map遍历
JAVA
import java.util.HashMap;
import java.util.Map;
public class MapTraversal {
public static void main(String[] args) {
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
scores.put("Bob", 88);
scores.put("Charlie", 92);
// 遍历entrySet
System.out.println("=== entrySet遍历 ===");
for (Map.Entry<String, Integer> entry : scores.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// Lambda遍历
System.out.println("=== Lambda遍历 ===");
scores.forEach((name, score) ->
System.out.println(name + "的分数是" + score));
}
}
TreeMap
TreeMap基于红黑树实现,键自动排序。
示例:TreeMap
JAVA
import java.util.Map;
import java.util.TreeMap;
public class TreeMapDemo {
public static void main(String[] args) {
Map<String, Integer> map = new TreeMap<>();
map.put("Charlie", 92);
map.put("Alice", 95);
map.put("Bob", 88);
// 按键排序
map.forEach((key, value) ->
System.out.println(key + ": " + value));
// Alice: 95
// Bob: 88
// Charlie: 92
}
}
LinkedHashMap
LinkedHashMap维护插入顺序。
示例:LinkedHashMap
JAVA
import java.util.LinkedHashMap;
import java.util.Map;
public class LinkedHashMapDemo {
public static void main(String[] args) {
Map<String, Integer> map = new LinkedHashMap<>();
map.put("Charlie", 92);
map.put("Alice", 95);
map.put("Bob", 88);
// 按插入顺序
map.forEach((key, value) ->
System.out.println(key + ": " + value));
// Charlie: 92
// Alice: 95
// Bob: 88
}
}
Map常用方法
| 方法 | 说明 |
|---|---|
put(K, V) |
添加键值对 |
get(K) |
获取值 |
getOrDefault(K, V) |
获取值,不存在返回默认值 |
putIfAbsent(K, V) |
键不存在时添加 |
remove(K) |
删除键值对 |
containsKey(K) |
是否包含键 |
containsValue(V) |
是否包含值 |
keySet() |
所有键的Set |
values() |
所有值的Collection |
entrySet() |
所有Entry的Set |
size() |
大小 |
isEmpty() |
是否为空 |
clear() |
清空 |
putAll(Map) |
添加所有 |
Map对比
| 特性 | HashMap | TreeMap | LinkedHashMap |
|---|---|---|---|
| 顺序 | 无序 | 排序 | 插入顺序 |
| 底层 | 哈希表 | 红黑树 | 链表+哈希表 |
| 性能 | O(1) | O(log n) | O(1) |
| null键 | 允许1个 | 不允许 | 允许1个 |
示例:词频统计
JAVA
import java.util.HashMap;
import java.util.Map;
public class WordCount {
public static Map<String, Integer> count(String text) {
Map<String, Integer> map = new HashMap<>();
String[] words = text.toLowerCase().split("\\s+");
for (String word : words) {
map.put(word, map.getOrDefault(word, 0) + 1);
}
return map;
}
public static void main(String[] args) {
String text = "hello world hello java world hello";
Map<String, Integer> counts = count(text);
counts.forEach((word, count) ->
System.out.println(word + ": " + count));
// hello: 3
// world: 2
// java: 1
}
}
示例:分组
JAVA
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class GroupBy {
public static Map<String, List<String>> groupByFirstChar(List<String> list) {
Map<String, List<String>> map = new HashMap<>();
for (String s : list) {
String key = s.substring(0, 1).toUpperCase();
map.computeIfAbsent(key, k -> new ArrayList<>()).add(s);
}
return map;
}
public static void main(String[] args) {
List<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
names.add("Charlie");
names.add("David");
names.add("Eve");
Map<String, List<String>> groups = groupByFirstChar(names);
groups.forEach((key, value) ->
System.out.println(key + ": " + value));
// A: [Alice]
// B: [Bob]
// C: [Charlie]
// D: [David]
// E: [Eve]
}
}
❓ 常见问题
Q HashMap的键可以是null吗?
A 可以,只能有一个null键。值可以有多个null。
Q HashMap如何判断键重复?
A 先比较hashCode,再比较equals,与HashSet类似。
Q HashMap线程安全吗?
A 不安全。多线程用ConcurrentHashMap。
📖 小节
- Map是键值对集合,键不重复
- HashMap无序,TreeMap排序,LinkedHashMap保序
- 遍历方式:keySet/values/entrySet/Lambda
- 常用方法:put/get/remove/containsKey/forEach
📝 作业
- 词频统计: 统计字符串中每个单词出现的次数
- 分组: 将学生按成绩等级分组(优秀/良好/及格/不及格)
- 缓存: 用HashMap实现一个简单的缓存
下一课
下一课我们将学习 泛型,了解Java泛型的使用。



