# 2026-07-29 集合框架(Collection Framework)基础练习(课堂练习用) > **说明**:以下习题围绕今日授课核心内容——**Java 集合框架入门(Collection Framework)** 展开,涵盖集合 vs 数组对比、ArrayList 基本操作(增删改查)、ArrayList 底层原理(容量/扩容/size)、包装类在集合中的应用等知识点。 > > 题目分为 **基础练习**(ArrayList 基本操作,3 题)和 **进阶挑战**(综合应用,2 题)。 --- # 第一部分:基础练习 > 以下练习围绕 ArrayList 的基本 CRUD 操作和常用方法,由浅入深。 --- ## 练习 1:学生信息录入系统 **难度**:⭐ **知识点**:ArrayList 创建、add() 添加元素、size() 获取个数、包装类应用 **场景描述**:学校需要一个简单的学生信息录入系统,使用 ArrayList 存储学生信息,要求使用包装类 `Integer` 表示年龄。 **题目要求**: **步骤 1**:创建一个 `Student` 类,包含以下属性: | 属性 | 类型 | 说明 | |------|------|------| | `name` | `String` | 姓名 | | `age` | `Integer` | 年龄(使用包装类) | | `studentId` | `String` | 学号 | 要求:提供 full getter/setter 方法和无参/全参构造方法。 **步骤 2**:在 `StudentManager` 类的 `main` 方法中,完成以下操作: ```java public class StudentManager { public static void main(String[] args) { // 1. 创建一个 ArrayList,用于存储 Student 对象 // 提示:ArrayList students = new ArrayList<>(); // 2. 创建 4 个 Student 对象,信息如下: // 张三, 20, S001 // 李四, 21, S002 // 王五, 19, S003 // 赵六, 22, S004 // 3. 将 4 个学生对象添加到 ArrayList 中 // 4. 输出 ArrayList 中的学生总数(使用 size() 方法) // 5. 遍历 ArrayList,打印每个学生的信息(使用 for 循环 + get() 方法) // 输出格式:学号:S001, 姓名:张三, 年龄:20 } } ``` **预期输出**: ``` 学生总数:4 ========== 学生列表 ========== 学号:S001, 姓名:张三, 年龄:20 学号:S002, 姓名:李四, 年龄:21 学号:S003, 姓名:王五, 年龄:19 学号:S004, 姓名:赵六, 年龄:22 ``` **提示**: - 创建 ArrayList 的语法:`ArrayList list = new ArrayList<>();` - 添加元素:`list.add(student);` - 获取元素个数:`list.size()` - 获取指定索引元素:`list.get(index)` --- ## 练习 2:学生信息维护——增删改查 **难度**:⭐⭐ **知识点**:ArrayList 的 add()/remove()/set()/get()/isEmpty() 方法 **场景描述**:基于练习 1 的 Student 类,实现学生信息的增删改查功能。 **题目**:在 `StudentManager` 类的 `main` 方法中,基于已有学生列表,依次完成以下操作: ```java // 假设已有练习 1 中的 students 列表(张三、李四、王五、赵六) // 1. 判断列表是否为空(使用 isEmpty()),输出结果 // 2. 查询学号为 S003 的学生(遍历查找),输出其信息 // 3. 修改学号为 S002 的学生姓名将"李四"改为"李思" // 4. 删除学号为 S004 的学生(赵六) // 5. 在索引 1 的位置插入一个新学生:孙七, 18, S005 // 6. 再次遍历输出所有学生信息 // 7. 查看此时列表中学生总数 ``` **预期输出**: ``` 列表是否为空?false --- 查询结果 --- 学号:S003, 姓名:王五, 年龄:19 已修改学号 S002 的学生姓名为:李思 已删除学号 S004 的学生:赵六 已在索引 1 处插入新学生:孙七 ========== 最终学生列表 ========== 学号:S001, 姓名:张三, 年龄:20 学号:S005, 姓名:孙七, 年龄:18 学号:S002, 姓名:李思, 年龄:21 学号:S003, 姓名:王五, 年龄:19 当前学生总数:4 ``` **提示**: - `list.isEmpty()` — 判断是否为空 - `list.set(index, newValue)` — 修改指定位置的元素 - `list.remove(index)` — 删除指定位置的元素 - `list.add(index, element)` — 在指定位置插入元素 --- ## 练习 3:学生年龄统计与分析 **难度**:⭐⭐ **知识点**:ArrayList 遍历、条件筛选、包装类自动拆箱、统计计算 **场景描述**:对学生列表进行年龄统计分析。 **题目**:在 `StudentManager` 类的 `main` 方法中,对学生列表进行以下统计: ```java // 假设已有练习 1 中的 students 列表(张三、李四、王五、赵六) // 1. 计算所有学生的平均年龄(注意:age 是 Integer 类型,参与运算时会自动拆箱) // 输出格式:"平均年龄:XX.X" // 2. 统计年龄 >= 20 岁的学生,输出他们的信息 // 输出格式: // 年龄 >= 20 岁的学生: // 学号:S001, 姓名:张三, 年龄:20 // ... // 3. 找出年龄最大的学生,输出其信息 // 输出格式:"年龄最大的学生:学号:S002, 姓名:李四, 年龄:21" // 4. 按年龄从小到大输出所有学生信息(冒泡排序或选择排序,基于 ArrayList) ``` **预期输出**: ``` ========== 年龄统计 ========== 平均年龄:20.5 ---------- 年龄 >= 20 岁 ---------- 学号:S001, 姓名:张三, 年龄:20 学号:S002, 姓名:李四, 年龄:21 学号:S004, 姓名:赵六, 年龄:22 ---------- 年龄最大的学生 ---------- 学号:S004, 姓名:赵六, 年龄:22 ---------- 按年龄排序(升序) ---------- 学号:S003, 姓名:王五, 年龄:19 学号:S001, 姓名:张三, 年龄:20 学号:S002, 姓名:李四, 年龄:21 学号:S004, 姓名:赵六, 年龄:22 ``` **思考题**: 1. 包装类 `Integer` 参与算术运算时,底层发生了什么?(提示:自动拆箱) 2. 如果 `Student` 的 `age` 属性为 `null`,直接参与 `age.intValue()` 或算术运算会怎样? --- # 第二部分:进阶挑战 > 以下练习综合运用 ArrayList、包装类、面向对象思想,模拟真实业务场景。 --- ## 进阶 1:学生选课管理系统 **难度**:⭐⭐⭐ **知识点**:ArrayList 综合应用、contains()/indexOf() 方法、对象比较、remove() 按对象删除 **场景描述**:实现一个简单的学生选课管理系统,学生可以选择已开设的课程,也可以退选课程。 **题目要求**: **步骤 1**:在 `Student` 类中新增一个属性: ```java private ArrayList courses; // 已选课程列表 ``` 并提供 getter/setter 方法。在构造方法中初始化 `courses = new ArrayList<>();` **步骤 2**:在 `CourseManager` 类中实现以下功能: ```java public class CourseManager { public static void main(String[] args) { // 1. 创建一个学生对象:张三, 20, S001 // 2. 为该学生添加 3 门课程:"Java基础", "数据结构", "数据库原理" // 提示:student.getCourses().add("课程名"); // 3. 输出该学生的已选课程列表 // 输出格式:"张三的已选课程:[Java基础, 数据结构, 数据库原理]" // 4. 判断是否已选"数据结构"(使用 contains() 方法) // 输出:"是否已选数据结构?true" // 5. 退选"数据结构"课程(使用 remove() 方法按对象删除) // 输出:"已退选课程:数据结构" // 6. 再次输出该学生的已选课程列表 // 输出格式:"退选后的课程:[Java基础, 数据库原理]" // 7. 查询"Java基础"课程的索引位置(使用 indexOf() 方法) // 输出:"'Java基础'的索引位置:0" } } ``` **预期输出**: ``` 张三的已选课程:[Java基础, 数据结构, 数据库原理] 是否已选数据结构?true 已退选课程:数据结构 退选后的课程:[Java基础, 数据库原理] 'Java基础'的索引位置:0 ``` **提示**: - `list.contains(obj)` — 判断是否包含某个元素(依赖 `equals()` 方法) - `list.indexOf(obj)` — 返回元素第一次出现的索引,不存在返回 -1 - `list.remove(Object o)` — 按对象删除(注意这里是按元素值删除,不是按索引) **思考题**: 1. `remove("数据结构")` 和 `remove(1)` 有什么区别?参数类型不同时,调用的是哪个重载方法? 2. `contains()` 方法判断对象是否存在的依据是什么? --- ## 进阶 2:教室座位管理系统 **难度**:⭐⭐⭐⭐ **知识点**:ArrayList 作为对象属性、二维结构模拟(ArrayList 嵌套)、集合与包装类综合应用 **场景描述**:一个教室有 4 排座位,每排有 5 个座位。使用 `ArrayList` 模拟教室座位分配,每个座位可以坐一个学生或为空(`null`)。 **题目要求**: **步骤 1**:创建一个 `Classroom` 类: ```java public class Classroom { private String className; // 教室名称 private ArrayList> seats; // 座位表(4排 x 5列) // 构造方法:初始化教室名称,创建 4 排,每排初始化为 5 个 null 座位 public Classroom(String className) { this.className = className; this.seats = new ArrayList<>(); for (int i = 0; i < 4; i++) { // 4 排 ArrayList row = new ArrayList<>(); for (int j = 0; j < 5; j++) { // 每排 5 个座位 row.add(null); // 初始为空座位 } seats.add(row); } } // 给学生分配座位(指定排和列) public boolean assignSeat(int row, int col, Student student) { // 检查行列是否越界(0~3, 0~4) // 检查座位是否已被占用(不为 null) // 如果可用,将学生放入该座位,返回 true // 否则返回 false } // 显示座位分配情况 public void displaySeats() { // 遍历所有座位,输出格式: // 第1排:[张三, 李四, 空, 王五, 空] // 第2排:[空, 赵六, 空, 空, 空] // ... } // 统计空座位数量 public int countEmptySeats() { // 遍历所有座位,统计 null 的数量 } // 统计某排已坐人数 public int countOccupiedInRow(int row) { // 遍历指定排,统计非 null 的数量 } } ``` **步骤 2**:在 `Classroom` 类的 `main` 方法中,测试座位管理: ```java public static void main(String[] args) { // 1. 创建一个教室 "A101" Classroom classroom = new Classroom("A101"); // 2. 分配座位: // 张三 -> 第1排第1座 // 李四 -> 第1排第2座 // 王五 -> 第3排第4座 // 赵六 -> 第2排第3座 // 3. 显示所有座位分配情况 // 4. 尝试给已占用的座位再次分配(第1排第1座已有张三),观察返回值 // 5. 统计空座位总数 // 6. 统计第1排已坐人数 } ``` **预期输出**: ``` ========== A101 教室座位分配 ========== 第1排:[张三, 李四, 空, 空, 空] 第2排:[空, 空, 赵六, 空, 空] 第3排:[空, 空, 空, 王五, 空] 第4排:[空, 空, 空, 空, 空] 第1排第1座已被占用,分配失败! 空座位总数:17 第1排已坐人数:2 ``` **提示**: - `ArrayList` 嵌套:`ArrayList>` 模拟二维结构 - 访问元素:`seats.get(row).get(col)` - 修改元素:`seats.get(row).set(col, student)` - `null` 表示空座位 **思考题**: 1. 用集合的嵌套模拟二维结构和用二维数组 `Student[][]` 相比,有什么优势? 2. 如果要支持动态增加排数或每排座位数,哪种数据结构更灵活? --- # 参考答案要点 ## 练习 1 参考 ```java // Student 类 public class Student { private String name; private Integer age; private String studentId; public Student() {} public Student(String name, Integer age, String studentId) { this.name = name; this.age = age; this.studentId = studentId; } // getter / setter 省略 } // StudentManager 类 main 方法关键代码 ArrayList students = new ArrayList<>(); Student s1 = new Student("张三", 20, "S001"); Student s2 = new Student("李四", 21, "S002"); Student s3 = new Student("王五", 19, "S003"); Student s4 = new Student("赵六", 22, "S004"); students.add(s1); students.add(s2); students.add(s3); students.add(s4); System.out.println("学生总数:" + students.size()); for (int i = 0; i < students.size(); i++) { Student s = students.get(i); System.out.println("学号:" + s.getStudentId() + ", 姓名:" + s.getName() + ", 年龄:" + s.getAge()); } ``` ## 练习 2 参考 ```java // isEmpty() 判断 System.out.println("列表是否为空?" + students.isEmpty()); // 查询学号为 S003 的学生 for (int i = 0; i < students.size(); i++) { Student s = students.get(i); if ("S003".equals(s.getStudentId())) { System.out.println("学号:" + s.getStudentId() + ", 姓名:" + s.getName() + ", 年龄:" + s.getAge()); break; } } // 修改:将"李四"改为"李思" for (int i = 0; i < students.size(); i++) { Student s = students.get(i); if ("S002".equals(s.getStudentId())) { s.setName("李思"); break; } } // 删除赵六 students.remove(3); // 在索引 1 处插入新学生 students.add(1, new Student("孙七", 18, "S005")); ``` ## 练习 3 参考(排序部分) ```java // 冒泡排序(按年龄升序) for (int i = 0; i < students.size() - 1; i++) { for (int j = 0; j < students.size() - 1 - i; j++) { Student s1 = students.get(j); Student s2 = students.get(j + 1); if (s1.getAge() > s2.getAge()) { // 交换 Student temp = students.get(j); students.set(j, students.get(j + 1)); students.set(j + 1, temp); } } } ``` ## 进阶 1 参考(退选课程) ```java // 判断是否已选 System.out.println("是否已选数据结构?" + student.getCourses().contains("数据结构")); // 退选课程 student.getCourses().remove("数据结构"); // 查询索引 System.out.println("'Java基础'的索引位置:" + student.getCourses().indexOf("Java基础")); ``` ## 进阶 2 参考(assignSeat 方法) ```java public boolean assignSeat(int row, int col, Student student) { // 越界检查 if (row < 0 || row >= seats.size() || col < 0 || col >= seats.get(0).size()) { System.out.println("座位位置越界!"); return false; } // 检查是否已被占用 if (seats.get(row).get(col) != null) { System.out.println("第" + (row + 1) + "排第" + (col + 1) + "座已被占用,分配失败!"); return false; } // 分配座位 seats.get(row).set(col, student); return true; } ``` --- # 涵盖知识点总览 | 知识点 | 对应练习 | 说明 | |--------|---------|------| | ArrayList 创建与元素添加 | 练习 1 | `new ArrayList<>()`, `add()` | | ArrayList 遍历 | 练习 1、2、3 | `for` + `get()`, `size()` | | ArrayList 修改与删除 | 练习 2 | `set()`, `remove(index)` | | ArrayList 插入 | 练习 2 | `add(index, element)` | | ArrayList 查询与判断 | 进阶 1 | `contains()`, `indexOf()` | | 包装类自动拆箱 | 练习 3 | `Integer` 参与算术运算 | | 条件筛选与统计 | 练习 3 | 遍历 + 条件判断 | | 对象排序(冒泡排序) | 练习 3 | ArrayList 中的元素交换 | | ArrayList 嵌套(二维结构) | 进阶 2 | `ArrayList>` | | null 在集合中的语义 | 进阶 2 | `null` 表示空座位 |