第 8 章 · 集合框架:List、Set、Map
本章目标:掌握 Java 集合框架核心接口与实现类——ArrayList、HashSet、HashMap;熟练使用 Iterator 遍历与删除;理解 Comparable 与 Comparator 排序规则;完成 toolkit-demo 商品列表与去重标签练习。
学时建议:4~5 小时(含 1.5 小时跟练)
前置:完成 ch04 数组与 String;ch05 面向对象;ch06 接口与枚举。
8.1 集合框架概览
Java 集合位于 java.util 包,分为两大体系:
Collection(单列)
├── List — 有序、可重复(ArrayList、LinkedList)
├── Set — 不重复(HashSet、TreeSet)
└── Queue — 队列(LinkedList、PriorityQueue)
Map(双列,键值对)
└── HashMap、TreeMap、LinkedHashMap
| 接口 | 典型实现 | 特点 |
|---|---|---|
List | ArrayList | 随机访问快,尾部增删快 |
Set | HashSet | 基于哈希,无序、不重复 |
Map | HashMap | 键唯一,查找 O(1) 平均 |
工程原则:默认选 ArrayList 与 HashMap;需要排序时用 TreeSet / TreeMap 或 Collections.sort()。
8.2 ArrayList 基础
ArrayList 底层是动态数组,适合读多写少、按索引访问的场景。
import java.util.ArrayList;
import java.util.List;
public class ListDemo {
public static void main(String[] args) {
List<String> books = new ArrayList<>();
books.add("Java 基础");
books.add("Web 开发");
books.add("数据分析");
books.add("Web 开发"); // List 允许重复
System.out.println(books.size()); // 4
System.out.println(books.get(0)); // Java 基础
System.out.println(books.contains("Web 开发")); // true
books.remove(1);
books.set(0, "Java 进阶");
for (int i = 0; i < books.size(); i++) {
System.out.println(i + ": " + books.get(i));
}
}
}
| 方法 | 说明 |
|---|---|
add(e) / add(i, e) | 追加或插入 |
get(i) | 按索引取值 |
remove(i) / remove(o) | 按索引或对象删除 |
size() | 元素个数 |
isEmpty() | 是否为空 |
clear() | 清空 |
泛型:List<String> 编译期检查类型,避免 (String) list.get(0) 强转。
8.3 HashSet 去重
HashSet 基于 HashMap 实现,元素不重复,不保证顺序。
import java.util.HashSet;
import java.util.Set;
public class SetDemo {
public static void main(String[] args) {
Set<String> tags = new HashSet<>();
tags.add("热销");
tags.add("新品");
tags.add("热销"); // 重复元素被忽略
tags.add("限时");
System.out.println(tags.size()); // 3
for (String tag : tags) {
System.out.println(tag);
}
if (tags.contains("新品")) {
tags.remove("新品");
}
}
}
| 场景 | 是否用 Set |
|---|---|
| 用户访问过的 URL 去重 | ✅ HashSet |
| 需要按插入顺序去重 | LinkedHashSet |
| 需要排序的去重 | TreeSet |
| 需要按下标访问 | ❌ 用 List |
注意:自定义类放入 HashSet 需正确实现 equals() 与 hashCode()(ch05 §5.6 已学,两者必须成对重写)。
8.4 HashMap 键值映射
HashMap 是最常用的 Map 实现,键唯一,允许一个 null 键。
import java.util.HashMap;
import java.util.Map;
public class MapDemo {
public static void main(String[] args) {
Map<String, Integer> stock = new HashMap<>();
stock.put("BK-001", 120);
stock.put("BK-002", 45);
stock.put("BK-003", 89);
System.out.println(stock.get("BK-001")); // 120
System.out.println(stock.getOrDefault("BK-999", 0)); // 0
stock.put("BK-002", 50); // 覆盖旧值
for (Map.Entry<String, Integer> entry : stock.entrySet()) {
System.out.println(entry.getKey() + " => " + entry.getValue());
}
for (String sku : stock.keySet()) {
System.out.println(sku);
}
}
}
| 方法 | 说明 |
|---|---|
put(k, v) | 插入或更新 |
get(k) | 取值,无键返回 null |
getOrDefault(k, default) | 安全取值 |
containsKey(k) | 是否包含键 |
entrySet() | 键值对集合,便于遍历 |
toolkit-demo 场景:用 Map<String, Integer> 统计日志中各路径出现次数。
8.5 遍历方式对比
List<String> items = new ArrayList<>();
items.add("A");
items.add("B");
items.add("C");
// 1. for-each(推荐)
for (String s : items) {
System.out.println(s);
}
// 2. 索引 for(需要下标时)
for (int i = 0; i < items.size(); i++) {
System.out.println(items.get(i));
}
// 3. Iterator(遍历时安全删除)
import java.util.Iterator;
Iterator<String> it = items.iterator();
while (it.hasNext()) {
String s = it.next();
if (s.equals("B")) {
it.remove(); // 不能用 items.remove(s) 在 for-each 中
}
}
| 方式 | 适用 |
|---|---|
| for-each | 只读遍历 |
| Iterator | 遍历时删除元素 |
| 索引 for | 需要位置信息 |
8.6 Iterator 详解
Iterator 是集合的统一遍历接口:
import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;
public class IteratorDemo {
public static void main(String[] args) {
List<Integer> nums = new ArrayList<>();
nums.add(1);
nums.add(2);
nums.add(3);
nums.add(4);
Iterator<Integer> it = nums.iterator();
while (it.hasNext()) {
int n = it.next();
if (n % 2 == 0) {
it.remove();
}
}
System.out.println(nums); // [1, 3]
}
}
| 方法 | 说明 |
|---|---|
hasNext() | 是否还有下一个 |
next() | 取下一个并前进 |
remove() | 删除当前元素(只能调用一次 next 后) |
ListIterator(List 专用)还支持 previous() 与双向遍历,选修了解即可。