|
|
@@ -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、调用实现类特有方法、开闭原则 | ⭐⭐⭐ |
|
|
|
+| 第 2 题 | MyArray 可变数组 | 构造方法、数组扩容、增删改查、元素前移、冒泡排序 | ⭐⭐⭐⭐⭐ |
|
|
|
+| 第 3 题 | 在线考试系统(模板方法) | 抽象类、模板方法、final、方法重写 | ⭐⭐⭐⭐⭐ |
|