20260729-集合框架练习.md 15 KB

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 方法中,完成以下操作:

public class StudentManager {
    public static void main(String[] args) {
        // 1. 创建一个 ArrayList,用于存储 Student 对象
        //    提示:ArrayList<Student> 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<Student> list = new ArrayList<>();
  • 添加元素:list.add(student);
  • 获取元素个数:list.size()
  • 获取指定索引元素:list.get(index)

练习 2:学生信息维护——增删改查

难度:⭐⭐
知识点:ArrayList 的 add()/remove()/set()/get()/isEmpty() 方法

场景描述:基于练习 1 的 Student 类,实现学生信息的增删改查功能。

题目:在 StudentManager 类的 main 方法中,基于已有学生列表,依次完成以下操作:

// 假设已有练习 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 方法中,对学生列表进行以下统计:

// 假设已有练习 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. 如果 Studentage 属性为 null,直接参与 age.intValue() 或算术运算会怎样?

第二部分:进阶挑战

以下练习综合运用 ArrayList、包装类、面向对象思想,模拟真实业务场景。


进阶 1:学生选课管理系统

难度:⭐⭐⭐
知识点:ArrayList 综合应用、contains()/indexOf() 方法、对象比较、remove() 按对象删除

场景描述:实现一个简单的学生选课管理系统,学生可以选择已开设的课程,也可以退选课程。

题目要求

步骤 1:在 Student 类中新增一个属性:

private ArrayList<String> courses;  // 已选课程列表

并提供 getter/setter 方法。在构造方法中初始化 courses = new ArrayList<>();

步骤 2:在 CourseManager 类中实现以下功能:

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 类:

public class Classroom {
    private String className;                   // 教室名称
    private ArrayList<ArrayList<Student>> 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<Student> 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 方法中,测试座位管理:

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<ArrayList<Student>> 模拟二维结构
  • 访问元素:seats.get(row).get(col)
  • 修改元素:seats.get(row).set(col, student)
  • null 表示空座位

思考题

  1. 用集合的嵌套模拟二维结构和用二维数组 Student[][] 相比,有什么优势?
  2. 如果要支持动态增加排数或每排座位数,哪种数据结构更灵活?

参考答案要点

练习 1 参考

// 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<Student> 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 参考

// 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 参考(排序部分)

// 冒泡排序(按年龄升序)
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 参考(退选课程)

// 判断是否已选
System.out.println("是否已选数据结构?"
    + student.getCourses().contains("数据结构"));

// 退选课程
student.getCourses().remove("数据结构");

// 查询索引
System.out.println("'Java基础'的索引位置:"
    + student.getCourses().indexOf("Java基础"));

进阶 2 参考(assignSeat 方法)

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<ArrayList<Student>>
null 在集合中的语义 进阶 2 null 表示空座位