🧺 集合入门
数组的"升级版" · List/Set/Map 怎么选 · 常用方法演练
1. 什么是集合?为什么有了数组还要它?
数组的痛点:长度固定(要扩容得自己写拷贝)、只能按下标访问、方法少。
集合(Collection):Java 提供的"高级容器",帮你管增删改查。三大家族:
🧺 类比:
List = 排队买奶茶的队伍(有顺序,可以重复,按号找位置)
Set = 储物柜(每个东西独一无二,不能重复放)
Map = 字典/通讯录(一个名字对应一个号码——键值对)
List = 排队买奶茶的队伍(有顺序,可以重复,按号找位置)
Set = 储物柜(每个东西独一无二,不能重复放)
Map = 字典/通讯录(一个名字对应一个号码——键值对)
| 接口 | 特点 | 常用实现 | 场景 |
|---|---|---|---|
| List | 有序、可重复 | ArrayList | 列表(菜单、学生名单) |
| Set | 无序、不可重复 | HashSet | 去重(已报到的学号) |
| Map | 键值对,键唯一 | HashMap | 映射(学号→学生、配置项) |
🎯 记忆
- 泛型写法:List<String> = 只装 String 的列表(<> 里写元素类型)
- 面试题"数组和 ArrayList 区别":长度可变、方法丰富、自动扩容——答案先记住这几句
2. List 的增删改查(先会这一套就够用)
ArrayList 常用操作
import java.util.ArrayList;
import java.util.List;
List<String> names = new ArrayList<>(); // 创建(后面的 <> 可省略)
names.add("小明"); // 增:末尾添加
names.add("小红");
names.add(0, "小刚"); // 增:插到指定位置
names.get(1); // 查:按下标取(0 开始)
names.size(); // 查:个数(不是 length!)
names.contains("小明"); // 查:是否包含
names.set(0, "小刚改"); // 改:替换指定位置
names.remove("小红"); // 删:按值删除
names.remove(0); // 删:按下标删除
// 遍历(两种)
for (String n : names) System.out.println(n); // 增强 for
for (int i = 0; i < names.size(); i++) { ... } // 普通 for(要下标时)
🎯 对比数组记住
- 长度:数组 arr.length / 集合 list.size()(一个没括号一个有)
- 取值:数组 arr[i] / 集合 list.get(i)
- 遍历删除要小心:用迭代器或倒序(进阶页讲,先别踩坑:增强 for(和迭代器)遍历时 remove 会抛
ConcurrentModificationException;普通下标 for 里 remove 不报错,但会漏掉元素)
3. Map:键值对怎么用?
HashMap 常用操作
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> scores = new HashMap<>();
// 键(名字) 值(分数)
scores.put("小明", 95); // 增/改:放一个键值对(键已存在则覆盖)
scores.put("小红", 88);
Integer score = scores.get("小明"); // 查:按键取值,键不存在返回 null
// 注意:若写成 int score = ... ,键不存在时会因自动拆箱抛 NullPointerException
int safe = scores.getOrDefault("小明", 0); // 安全写法:给默认值
boolean has = scores.containsKey("小明"); // 查:键是否存在
int size = scores.size(); // 查:有多少个键值对
scores.remove("小红"); // 删:按键删除
// 遍历:取出每一对
for (Map.Entry<String, Integer> e : scores.entrySet()) {
System.out.println(e.getKey() + " = " + e.getValue());
}
// 经典用法:统计出现次数(高频!)
Map<Character, Integer> count = new HashMap<>();
for (char c : str.toCharArray()) {
count.put(c, count.getOrDefault(c, 0) + 1); // 没出现过算 0,加 1
}
🎯 重点
- Map 三大操作:put(放)、get(取)、containsKey(查有没有)
- getOrDefault 是统计次数的神器
- Map 不是 Collection 体系(它是独立接口),但属于"集合框架"大家庭
4. Set 和"怎么选"的决策表?
HashSet:去重神器
import java.util.HashSet;
import java.util.Set;
Set<Integer> ids = new HashSet<>();
ids.add(1);
ids.add(2);
ids.add(1); // 重复添加无效!Set 里还是 {1, 2}
System.out.println(ids.size()); // 2
// 经典用途:去重
int[] arr = {1,2,2,3,3,3};
Set<Integer> unique = new HashSet<>();
for (int x : arr) unique.add(x);
// unique = {1, 2, 3}
选择口诀:
- 要顺序、可重复 → List(ArrayList)
- 要去重、判断存在 → Set(HashSet)
- 要按键找值 → Map(HashMap)
- 90% 的场景这三个默认实现就够,别纠结
✍️ 练习题(动手写!)
- 1. 创建一个 List<Integer>,添加 1~10,删除偶数,打印结果
- 2. 用 Map 统计一句话里每个单词出现的次数
- 3. 用 Set 找出数组 {3,1,4,1,5,9,2,6,5,3} 去重后的结果并排序(提示:先 Set 再转 List 用 Collections.sort)
- 4. 学生管理小系统:List<Student> 增删改查(结合面向对象页的 Student 类)
- 5. 思考:为什么 List 查"包含"比 Set 慢?(Set 底层是哈希,O(1);List 要一个个找,O(n)——进阶模块详解)