Browse Source

feat: 课后作业补充第2题(MyArray可变数组)和第3题(模板方法在线考试系统),分别从构造方法练习和抽象类练习中迁移

WanJL 7 hours ago
parent
commit
a4b84214ed
1 changed files with 233 additions and 6 deletions
  1. 233 6
      课后作业/2026年7月24日-作业.md

+ 233 - 6
课后作业/2026年7月24日-作业.md

@@ -26,12 +26,19 @@
 ```
 ```
 提交\
 提交\
 └─ 张三\
 └─ 张三\
-    └─ p1_smarthome\             ← 第 1 题的包
-        ├─ SmartDevice.java        ← 接口
-        ├─ Light.java              ← 实现类(特有:调色)
-        ├─ AirConditioner.java     ← 实现类(特有:定时)
-        ├─ RobotVacuum.java        ← 实现类(特有:清洁模式)
-        └─ SmartHomeController.java ← 测试类(多态 + instanceof + 向下转型)
+    ├─ p1_smarthome\             ← 第 1 题的包
+    │   ├─ SmartDevice.java        ← 接口
+    │   ├─ Light.java              ← 实现类(特有:调色)
+    │   ├─ AirConditioner.java     ← 实现类(特有:定时)
+    │   ├─ RobotVacuum.java        ← 实现类(特有:清洁模式)
+    │   └─ SmartHomeController.java ← 测试类(多态 + instanceof)
+    ├─ p2_myarray\               ← 第 2 题的包
+    │   └─ MyArray.java + MyArrayTest.java
+    └─ p3_exam\                  ← 第 3 题的包
+        ├─ ExamTemplate.java       ← 抽象类(模板方法)
+        ├─ JavaExam.java           ← 子类
+        ├─ MathExam.java           ← 子类
+        └─ ExamTest.java           ← 测试类
 ```
 ```
 
 
 > ⚠ **注意**:包名必须严格按题目要求书写(全小写),目录结构必须与包结构一致。
 > ⚠ **注意**:包名必须严格按题目要求书写(全小写),目录结构必须与包结构一致。
@@ -277,8 +284,228 @@
 
 
 ---
 ---
 
 
+## 第 2 题:综合大挑战——MyArray 可变数组(动态数组底层实现)⭐⭐⭐⭐⭐
+
+**包名**:`p2_myarray`
+
+**知识点**:构造方法、数组扩容、方法封装、增删改查、元素前移、冒泡排序
+
+> 模仿 `ArrayList` 的底层原理,自己动手实现一个可变数组(动态数组)。
+
+### 需求背景
+
+Java 中普通数组 `int[]` 一旦创建,长度就固定了,无法动态增减元素。请自行实现一个 **可变整型数组** `MyArray` 类,内部使用 `int[]` 存储数据,对外提供便捷的增删改查方法。
+
+### 实体类说明:MyArray
+
+**私有属性**:
+
+| 属性 | 类型 | 说明 |
+|------|------|------|
+| `data` | `int[]` | 内部真正存储数据的数组 |
+| `size` | `int` | 当前已存储的元素个数(不是数组长度) |
+
+**构造方法**:
+
+| 构造方法 | 说明 |
+|---------|------|
+| `MyArray()` | 无参构造,默认初始化容量为 **10** 的数组 |
+| `MyArray(int capacity)` | 指定初始容量,如果传入的容量 ≤ 0,则使用默认容量 10 |
+
+### 核心方法列表(共 11 个)
+
+#### 1. 添加元素 — `add(int element)`
+- 如果内部数组已满,自动扩容为当前容量的 **1.5 倍**(`data.length * 3 / 2`)
+- 扩容步骤:创建新数组 → 复制旧元素 → 替换 `data` 引用
+- 将新元素存入 `data[size]`,`size` 自增 1
+
+#### 2. 获取元素 — `get(int index)`
+- 下标越界时输出 `"下标越界,无法获取元素"`,返回 `-1`
+- 否则返回 `data[index]`
+
+#### 3. 修改元素 — `set(int index, int element)`
+- 下标越界时输出 `"下标越界,无法修改元素"`
+- 否则将 `data[index]` 赋值为 `element`
+
+#### 4. 获取长度 — `size()`
+- 返回 `size` 属性值
+
+#### 5. 获取容量 — `capacity()`
+- 返回 `data.length`
+
+#### 6. 判断是否为空 — `isEmpty()`
+- `size == 0` 返回 `true`,否则 `false`
+
+#### 7. 查找元素下标 — `indexOf(int element)`
+- 从前向后遍历,找到第一个匹配的元素下标,没找到返回 `-1`
+
+#### 8. 判断是否包含 — `contains(int element)`
+- 调用 `indexOf()`,根据返回值是否为 `-1` 判断
+
+#### 9. 删除指定位置的元素 — `remove(int index)`
+- 下标越界时输出 `"下标越界,无法删除元素"`,返回 `-1`
+- 否则:保存被删除的值 → 后面元素前移一位 → `size--` → 返回被删除的值
+
+#### 10. 删除指定值的元素 — `removeByValue(int element)`
+- 调用 `indexOf()` 获取下标
+- 下标为 `-1` 则输出 `"未找到该元素,删除失败"`,返回 `false`
+- 否则调用 `remove(index)`,返回 `true`
+
+#### 11. 数组排序 — `sort(boolean ascending)`
+- `true` 升序,`false` 降序
+- 使用**冒泡排序**,只对 `data[0] ~ data[size-1]` 排序
+
+### 辅助方法
+
+#### `print()`
+- 遍历输出格式:`[元素1, 元素2, 元素3, ...]`
+- 空数组输出 `[]`
+
+#### `clear()`
+- 将 `size` 置为 `0`(内部数组保留)
+
+### 测试类要求
+
+**`MyArrayTest` 类**:
+
+```java
+public class MyArrayTest {
+    public static void main(String[] args) {
+        // 1. 创建一个初始容量为 3 的 MyArray 对象
+        MyArray arr = new MyArray(3);
+
+        // 2. 输出初始状态
+        System.out.println("初始容量:" + arr.capacity());   // 3
+        System.out.println("是否为空:" + arr.isEmpty());     // true
+
+        // 3. 添加 5 个元素(触发自动扩容)
+        for (int i = 1; i <= 5; i++) {
+            arr.add(i * 10);  // 添加 10, 20, 30, 40, 50
+        }
+        arr.print();           // [10, 20, 30, 40, 50]
+
+        // 4. 测试各个方法
+        System.out.println("元素个数:" + arr.size());        // 5
+        System.out.println("当前容量:" + arr.capacity());     // 6
+        System.out.println("下标2的元素:" + arr.get(2));     // 30
+        System.out.println("是否包含40:" + arr.contains(40)); // true
+        System.out.println("50的下标:" + arr.indexOf(50));   // 4
+
+        // 5. 测试修改
+        arr.set(1, 99);
+        arr.print();           // [10, 99, 30, 40, 50]
+
+        // 6. 测试删除
+        int deleted = arr.remove(2);
+        System.out.println("被删除的元素:" + deleted);       // 30
+        arr.print();           // [10, 99, 40, 50]
+
+        // 7. 测试按值删除
+        arr.removeByValue(10);
+        arr.print();           // [99, 40, 50]
+
+        // 8. 测试升序排序
+        arr.sort(true);
+        arr.print();           // [40, 50, 99]
+
+        // 9. 测试降序排序
+        arr.sort(false);
+        arr.print();           // [99, 50, 40]
+
+        // 10. 测试越界访问
+        System.out.println(arr.get(10));  // 下标越界,无法获取元素 → -1
+        arr.remove(10);                   // 下标越界,无法删除元素 → -1
+    }
+}
+```
+
+### 思考题
+
+1. 如果 `add()` 方法中每次只扩容 1 个容量(`data.length + 1`),当添加大量元素时性能会怎样?为什么选择 1.5 倍?
+2. `remove()` 方法中为什么要将后面的元素向前移动?如果删除的是最后一个元素还需要移动吗?
+3. 如何将 `MyArray` 改造为支持任意类型的 `MyArrayList<T>`?
+
+---
+
+## 第 3 题:模板方法设计模式——在线考试系统 ⭐⭐⭐⭐⭐
+
+**包名**:`p3_exam`
+
+**知识点**:抽象类、抽象方法、模板方法(`final`)、方法重写、继承
+
+> 模板方法模式(Template Method Pattern)是抽象类的经典应用场景。**父类定义算法的「骨架」,子类实现特定的「步骤」**。
+
+### 需求说明
+
+模拟一个「在线考试系统」,每门考试都需要经过以下步骤:
+
+1. **登录验证**(所有考试相同)
+2. **发放试卷**(所有考试相同)
+3. **考试进行中**(不同科目考试内容不同)← **抽象方法**
+4. **收卷评分**(不同科目评分标准不同)← **抽象方法**
+5. **公布成绩**(所有考试相同)
+
+### 类设计
+
+**`ExamTemplate` 抽象类**(父类):
+- **普通方法** `login()` —— 输出 `"考生登录系统,验证身份... 登录成功!"`
+- **普通方法** `deliverPaper()` —— 输出 `"发放试卷,考试开始!"`
+- **抽象方法** `void conductExam()` —— 考试进行中(不同科目不同)
+- **抽象方法** `void gradeExam()` —— 收卷评分(不同科目不同)
+- **普通方法** `announceResult()` —— 输出 `"成绩公布!请登录系统查看"`
+- **模板方法** `final void startExam()` —— 按顺序执行完整考试流程:
+  1. 调用 `login()`
+  2. 调用 `deliverPaper()`
+  3. 调用 `conductExam()`
+  4. 调用 `gradeExam()`
+  5. 调用 `announceResult()`
+
+**`JavaExam` 类**(继承 ExamTemplate):
+- **重写** `conductExam()` —— 输出 `"Java 考试进行中:编写代码,回答选择题..."`
+- **重写** `gradeExam()` —— 输出 `"Java 考试评分:检查代码正确性,选择题自动判分..."`
+
+**`MathExam` 类**(继承 ExamTemplate):
+- **重写** `conductExam()` —— 输出 `"数学考试进行中:解答微积分、线性代数题目..."`
+- **重写** `gradeExam()` —— 输出 `"数学考试评分:答案比对,步骤给分..."`
+
+### 测试类要求
+
+**`ExamTest` 类**:
+
+1. 创建 `JavaExam` 对象,调用 `startExam()` 方法
+2. 创建 `MathExam` 对象,调用 `startExam()` 方法
+3. 观察:**考试流程的「骨架」由父类定义,子类只需实现「考试内容」和「评分方式」两个步骤**
+
+### 预期输出
+
+```
+========== Java 考试 ==========
+考生登录系统,验证身份... 登录成功!
+发放试卷,考试开始!
+Java 考试进行中:编写代码,回答选择题...
+Java 考试评分:检查代码正确性,选择题自动判分...
+成绩公布!请登录系统查看
+
+========== 数学考试 ==========
+考生登录系统,验证身份... 登录成功!
+发放试卷,考试开始!
+数学考试进行中:解答微积分、线性代数题目...
+数学考试评分:答案比对,步骤给分...
+成绩公布!请登录系统查看
+```
+
+### 思考题
+
+1. `startExam()` 方法为什么用 `final` 修饰?如果不加 `final` 会怎样?
+2. 模板方法模式的核心思想是什么?和「普通继承 + 方法重写」有什么区别?
+3. 你在日常生活中有哪些场景可以用模板方法模式来描述?(例如:做饭流程、工作日报提交流程等)
+
+---
+
 ## 📋 题目总览
 ## 📋 题目总览
 
 
 | 题号 | 名称 | 核心知识点 | 难度 |
 | 题号 | 名称 | 核心知识点 | 难度 |
 |------|------|-----------|------|
 |------|------|-----------|------|
 | 第 1 题 | 智能家居控制系统 | 接口多态、向上转型/向下转型、instanceof、调用实现类特有方法、开闭原则 | ⭐⭐⭐ |
 | 第 1 题 | 智能家居控制系统 | 接口多态、向上转型/向下转型、instanceof、调用实现类特有方法、开闭原则 | ⭐⭐⭐ |
+| 第 2 题 | MyArray 可变数组 | 构造方法、数组扩容、增删改查、元素前移、冒泡排序 | ⭐⭐⭐⭐⭐ |
+| 第 3 题 | 在线考试系统(模板方法) | 抽象类、模板方法、final、方法重写 | ⭐⭐⭐⭐⭐ |