# JavaSE 重点核心编程题复习手册
> 本文档从 **课后作业**(`课后作业\`)和 **课堂练习题**(`课堂练习题\`)中,按 JavaSE 授课章节精选出每个章节的 **重点编程题** 与 **核心编程题**,用于期末复习与刷题。
>
> **筛选原则**:
> - 🎯 **核心编程题**:每个章节必须掌握的经典题目,直接对应章节核心知识点
> - ⭐ **重点编程题**:综合性强、笔试面试高频、值得反复练习的进阶题目
>
> 每个题目保留了原文档的核心要求、示例输出与实现提示(详见各章节原文)。
---
## 目录
| 章节 | 对应日期 | 核心知识点 |
|------|---------|-----------|
| 第 1 章 运算符与流程控制 | 07-14 | if-else / 逻辑与位运算 / 三目 / 循环 |
| 第 2 章 数组基础 | 07-15 | 数组创建 / 遍历 / 增删改查 / 去重 |
| 第 3 章 数组进阶与排序 | 07-16 | 冒泡 / 选择 / 插入排序、Scanner |
| 第 4 章 Java 方法 | 07-17 | 方法 4 种声明 / 数组参数 / Random |
| 第 5 章 面向对象基础与封装 | 07-20 | 类与对象 / private / setter / getter |
| 第 6 章 构造方法 | 07-21 | 无参/有参/重载 / this() / 对象数组 |
| 第 7 章 继承 | 07-22 | extends / super / 方法重写 / 多态雏形 |
| 第 8 章 抽象类与接口 | 07-23 | abstract / interface / 模板方法 |
| 第 9 章 多态 | 07-24 | 向上/向下转型 / instanceof / 动态数组 |
| 第 10 章 匿名内部类与 JavaAPI | 07-27 | 匿名内部类 / String / StringBuilder / Math / 时间日期 |
| 第 11 章 异常处理 | 07-28 | try-catch / throw / throws / 自定义异常 / finally |
| 第 12 章 集合框架(ArrayList) | 07-29 | ArrayList / 泛型 / 增删改查 / 底层扩容 |
| 第 13 章 LinkedList 与双链表 | 07-30 | Queue / Stack / Deque / 手写链表 |
| 第 14 章 Map 与迭代器 | 07-31 | Iterator / HashMap / TreeMap / keySet / entrySet |
| 第 15 章 比较器排序与可变参数 | 08-03 | Comparable / Comparator / Collections / 可变参数 / Lambda |
| 第 16 章 Stream 流与函数式编程 | 08-04 | filter / map / collect / 方法引用 / 期末大作业 |
| 第 17 章 File 与 IO 流 | 08-06 | File 类 / FileInputStream / FileOutputStream |
| 第 18 章 IO 缓冲流与字符流 | 08-07 | 缓冲流 / FileReader / FileWriter / BufferedReader |
| 第 19 章 对象序列化与多线程 | 08-08 | Serializable / 转换流 / Thread / Runnable / Callable |
| 第 20 章 多线程进阶 | 08-10 | 生命周期 / 优先级 / 守护线程 / synchronized |
| 第 21 章 volatile 与 Lock 锁 | 08-11 | volatile / ReentrantLock / 线程池 |
| 第 22 章 反射 | 08-12~13 | Class / Constructor / Field / Method / JUnit 模拟 |
---
# 第 1 章 运算符与流程控制(07-14)
> **出处**:`课后作业/2026年7月14日-作业.md`
## 🎯 核心编程题
### 题目 1:判断闰年 ⭐
**知识点**:if-else、逻辑运算符、算术运算符
从键盘输入一个年份(整数),判断该年份是否为闰年。
**闰年规则(满足其一即可)**:
1. 能被 4 整除但不能被 100 整除;或者
2. 能被 400 整除
**要求**:定义 `int year` 变量;使用 `if-else` 分支结构;使用逻辑运算符 `&&` 和 `||`;输出 `xxxx 年是闰年` 或 `xxxx 年不是闰年`。
```java
// 核心判断:能被4整除但不能被100整除,或能被400整除
boolean isLeap = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
```
### 题目 2:三个数比大小 ⭐
**知识点**:三目运算符、if-else
定义三个整数变量 `a`、`b`、`c`,找出其中的最大值并输出。
- 方法一:使用三目运算符嵌套实现
- 方法二:使用 `if-else` 实现(两种方法都写在同一个文件中)
```java
int max = (a > b ? a : b) > c ? (a > b ? a : b) : c;
```
### 题目 3:水仙花数判定 ⭐⭐
**知识点**:算术运算符(`/`、`%`)、if-else
"水仙花数"指一个三位数,其各位数字的立方和等于该数本身。例如:`153 = 1³ + 5³ + 3³`。
```java
int num = 153;
int bai = num / 100; // 百位
int shi = num / 10 % 10; // 十位
int ge = num % 10; // 个位
// 判断 bai³ + shi³ + ge³ == num
```
### 题目 4:成绩等级判定(升级版)⭐⭐
**知识点**:if-else if-else、逻辑运算符、三目运算符
| 分数范围 | 等级 | 评价语 |
|---------|------|--------|
| 90 ≤ score ≤ 100 | A | 优秀,继续保持! |
| 80 ≤ score < 90 | B | 良好,再接再厉! |
| 70 ≤ score < 80 | C | 中等,还需努力! |
| 60 ≤ score < 70 | D | 及格,危险边缘! |
| 0 ≤ score < 60 | E | 不及格,加油啊! |
| 其他 | 无效 | 分数错误! |
额外使用**三目运算符**判断该成绩是否及格(≥ 60 为及格)。
### 题目 5:简易计算器 ⭐⭐
**知识点**:if-else、算术运算符、Scanner(选做)
定义两个整数 `a`、`b` 和字符变量 `operator`(取值为 `'+'`/`'-'`/`'*'`/`'/'`/`'%'`),用 `if-else if-else` 多分支判断输出运算结果。除号为 `/`、取模为 `%` 时需判断除数是否为 0,输出"除数不能为 0"。
## ⭐ 重点编程题
### 题目 6:数字加密系统 ⭐⭐⭐
**知识点**:算术运算符、位运算符、三目运算符、综合运用
设计一个 4 位数字加密系统:
1. 输入一个 4 位整数(如 `1234`)
2. 对每一位数字加 5 → 对 10 取余 → 第 1 位与第 4 位交换、第 2 位与第 3 位交换
3. 输出加密后的数字(可选:`加密结果 ^ 0xAA` 再异或)
### 题目 7:位运算权限系统 ⭐⭐⭐
**知识点**:位运算符(`&`、`|`、`~`、`<<`)、综合运用
用位运算实现权限控制:
```java
int READ = 1 << 0; // 0001 = 1 读权限
int WRITE = 1 << 1; // 0010 = 2 写权限
int EXECUTE = 1 << 2; // 0100 = 4 执行权限
int DELETE = 1 << 3; // 1000 = 8 删除权限
```
- 用 `|` 赋予权限:`userPerm = READ | WRITE | EXECUTE;` → 7
- 用 `&` 判断权限:`boolean hasWrite = (userPerm & WRITE) == WRITE;`
- 用 `& ~` 取消权限:`userPerm = userPerm & ~WRITE;` → 5
### 题目 8:程序员智商测试 ⭐⭐⭐
**知识点**:运算符优先级、自增/自减、短路特性
先手算再运行验证:
```java
int a = 5, b = 3, c = 2;
int result1 = a++ + ++b * c--; // 手算 + 验证
int x = 10, y = 4;
boolean flag = (x > y) && (++x > 10) || (y-- < 3); // 分析 && 短路
int m = 8, n = 3;
int r = m++ - --n + ++m - n--;
```
---
# 第 2 章 数组基础(07-15)
> **出处**:`课后作业/2026年7月15日-作业.md`、`课堂练习题/20260715-数组进阶练习.md`
## 🎯 核心编程题
### 题目 1:数组动态/静态初始化 ⭐
**知识点**:动态初始化 `new int[5]`、静态初始化 `{10,20,30,40,50}`、索引访问(注意索引从 0 开始)
### 题目 2:for 循环遍历数组 ⭐
**知识点**:for 循环、数组遍历、`arr.length` 属性
循环条件中必须使用 `arr.length` 获取数组长度,不能在代码中直接写死数字。
### 题目 3:遍历数组并求和 ⭐⭐
**知识点**:数组遍历、累加求和
定义整数数组 `{11, 22, 33, 44, 55}`,遍历计算总和。
### 题目 4:查找数组最大值 ⭐⭐
**知识点**:数组遍历、比较运算
定义一个变量 `max` 初始为第一个元素,遍历数组遇到更大的就更新 `max`。
### 题目 5:数组元素倒序输出 ⭐⭐
**知识点**:索引逆向操作
从 `arr.length - 1` 开始倒序遍历到 0,不改变原数组内容。
### 题目 6:统计奇偶数个数 ⭐⭐
**知识点**:数组遍历、if-else 分支、取模运算
`n % 2 == 0` 表示偶数,`n % 2 == 1` 表示奇数。
## ⭐ 重点编程题
### 题目 7:数组去重 ⭐⭐⭐
**知识点**:数组遍历、嵌套循环、新数组
定义数组 `{5, 2, 8, 2, 5, 9, 1, 8, 3}`,去除重复元素只保留第一次出现的,不能用 `Set` 集合。
- 先统计不重复元素个数,再创建新数组;遍历判断是否已存在。
### 题目 8:双色球号码生成器 ⭐⭐⭐⭐
**知识点**:数组、随机数、嵌套循环、去重
红球从 1~33 随机选 **6 个不重复**号码存入 `int[]` 数组;蓝球从 1~16 随机选 **1 个**。
```java
int num = (int)(Math.random() * 33) + 1; // 生成候选号码
// 与已生成的号码逐个比较,不重复才加入(去重)
```
### 题目 9:数组元素循环右移 ⭐⭐⭐
**知识点**:数组操作、循环、下标运算
`{1,2,3,4,5}` 循环右移 2 位 → `{4,5,1,2,3}`。在原数组上操作,`k = k % 数组长度` 处理 k 大于长度的情况。
---
# 第 3 章 数组进阶与排序(07-16)
> **出处**:`课后作业/2026年7月16日-作业.md`
## 🎯 核心编程题(三大排序算法必背)
### 题目 1:冒泡排序 — 数组升序 ⭐⭐⭐
**知识点**:冒泡排序、嵌套循环、变量交换
对 `{29, 10, 14, 37, 13, 33, 48, 22}` 升序排列,用 `Arrays.toString()` 输出前后对比。
- 外层循环控制冒泡轮数,共 `arr.length - 1` 轮
- 内层循环在 `[0, arr.length-1-i]` 区间相邻比较,前一个比后一个大就交换
- **优化**:用 `boolean` 标记本轮是否有交换,无交换提前结束
```java
for (int i = 0; i < arr.length - 1; i++) {
boolean swapped = false;
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp;
swapped = true;
}
}
if (!swapped) break; // 提前结束优化
}
```
### 题目 2:选择排序 — 数组降序 ⭐⭐⭐
**知识点**:选择排序、嵌套循环
对 `{56, 23, 89, 12, 45, 67, 34, 78}` **降序**排列。每轮从剩余元素中选出**最大值**放到未排序部分最前面,用 for 循环遍历输出(不用 `Arrays.toString()`)。
### 题目 3:插入排序 — 成绩排名 ⭐⭐⭐
**知识点**:插入排序、数组遍历
对成绩数组 `{88, 72, 93, 65, 81, 97, 78, 85}` 升序排列,每轮输出中间结果,排序完成后输出最低分和最高分。
- 将数组分为"已排序"和"未排序"两部分,从索引 1 开始
- 内层 `while` 从后往前扫描,比当前元素大的就后移
## ⭐ 重点编程题
### 题目 4:Scanner 学生信息采集系统 ⭐⭐⭐⭐
**知识点**:Scanner、数据类型、字符串拼接、条件判断
采集姓名/学号/年龄/性别/身高/体重/是否在校,计算 BMI(`weight / (height * height)`),按中国标准判定体型(偏瘦/正常/偏胖/肥胖)。
- **注意 `nextInt()` / `nextDouble()` 与 `nextLine()` 混用时的换行符陷阱**
- BMI 保留两位小数:`String.format("%.2f", bmi)` 或 `Math.round(bmi * 100) / 100.0`
- 进阶挑战:性别校验(非男非女提示重输)、年龄范围校验(0~120)
---
# 第 4 章 Java 方法(07-17)
> **出处**:`课后作业/2026年7月17日-作业.md`、`课堂练习题/20260717-Java方法基础练习.md`
> **方法 4 种声明方式**:
> 1. 无参无返回值(`public static void 方法名() {}`)
> 2. 有参无返回值(`public static void 方法名(参数) {}`)
> 3. 有参有返回值(`public static 类型 方法名(参数) {}`)
> 4. 无参有返回值(`public static 类型 方法名() {}`)
## 🎯 核心编程题
### 题目 1:方法 4 种声明方式(必做基础)⭐~⭐⭐
**知识点**:4 种方法声明
1. **无参无返回值**:`printInfoCard()` 打印个人信息卡片
2. **有参无返回值**:`printInvertedTriangle(int n)` 打印 n 行倒直角三角形(第 i 行打印 `n - i` 个 `*`)
3. **有参有返回值**:`average(int[] arr)` 计算数组平均值(注意整数除法丢失小数,用 `(double)求和 / arr.length`)
4. **无参有返回值**:`getGreeting()` 根据 `LocalTime.now().getHour()` 返回问候语
### 题目 2:方法中调用方法 — 温度转换 ⭐⭐
**知识点**:方法中调用另一个方法
```java
public static double celsiusToFahrenheit(double c) { return c * 9.0 / 5.0 + 32.0; }
public static double fahrenheitToCelsius(double f) { return (f - 32.0) * 5.0 / 9.0; }
public static void printTemperature(double c) {
// 调用上面两个方法,printf("%.2f") 保留两位小数输出 ℃ / ℉
}
```
### 题目 3:冒泡排序方法封装 ⭐⭐⭐
**知识点**:数组作为方法参数、冒泡排序
将冒泡排序封装为 `bubbleSort(int[] arr)` 方法,方法内部输出排序前后数组,main 中测试两组数据。
## ⭐ 重点编程题
### 题目 4:随机密码生成器 ⭐⭐⭐
**知识点**:Random、无参有返回值、字符串拼接
生成 8 位随机密码,每一位随机是大写字母(ASCII 65~90)或数字(48~57)。
```java
Random ran = new Random();
String password = "";
// 循环8次:ran.nextInt(2) 决定当前位是字母还是数字
// 字母:(char)(ran.nextInt(26) + 65);数字:(char)(ran.nextInt(10) + 48)
```
### 题目 5:数组随机打乱(Fisher-Yates 洗牌算法)⭐⭐⭐⭐
**知识点**:数组作为方法参数、Random、数组交换
```java
// 从最后一个元素往前遍历(i 从 length-1 到 1):
// 生成随机索引 j,范围 [0, i];交换 arr[i] 和 arr[j]
for (int i = arr.length - 1; i > 0; i--) {
int j = ran.nextInt(i + 1);
int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp;
}
```
### 题目 6:综合大作业 — 随机抽奖系统 ⭐⭐⭐⭐⭐
**知识点**:方法 4 种声明方式综合、数组参数、Random、方法中调用方法
拆分为多个方法:`initParticipants()`(返回 10 人姓名数组)、`printParticipants(String[] names)`(遍历打印)、`shuffleArray(String[] arr)`(洗牌)、`luckyDraw(String[] names)`(打乱后取第 1 个元素为中奖者)。
> **课堂 20 道方法练习题**(`课堂练习题/20260717-Java方法基础练习.md`):打印分隔线 / 九九乘法表 / 判断奇偶 / 打印质数(`Math.sqrt(n)` 优化)/ 三角形 / 等腰三角形 / 求和 / 三数最大值 / 圆面积 / 闰年 / 阶乘 / 验证码 / 骰子 / 随机颜色 RGB 等,均围绕 4 种方法声明。
---
# 第 5 章 面向对象基础与封装(07-20)
> **出处**:`课后作业/2026年7月20日-作业.md`、`课堂练习题/20260720-面向对象基础练习.md`
## 🎯 核心编程题
### 题目 1:学生类定义与对象创建 ⭐
**知识点**:类与对象、成员变量、成员方法
定义 `Student` 类(name / age / className),方法 `showInfo()` 输出信息、`study(String course)` 输出"张三 正在学习 Java"。main 中创建 2 个对象。注意同一个 `.java` 文件只能有一个 `public class`。
### 题目 2:员工信息封装(Emp 类)⭐⭐
**知识点**:封装(private、setter/getter)、this 关键字、合法性校验
私有属性 `id`/`name`/`salary`,标准 setter/getter(参数同名用 `this` 区分)。**`setSalary` 中薪资小于 0 输出"薪资不能为负数!"**。业务方法 `work()` 输出"工号 xxx 的员工 xxx 正在工作……"。
### 题目 3:数组排序工具类 — SortUtils ⭐⭐⭐
**知识点**:数组作为方法参数、三大排序算法、`Arrays.copyOf`
将冒泡排序(升序+提前结束优化)、选择排序(降序)、插入排序(升序)封装为三个方法。用 `Arrays.copyOf(arr, arr.length)` 创建副本,避免改变原数组。
## ⭐ 重点编程题
### 题目 4:方法重用的综合计算 — MathTools 工具类 ⭐⭐⭐
**知识点**:方法 4 种声明方式综合、质数算法、回文数算法、Random
| 方法 | 类型 | 说明 |
|------|------|------|
| `printPrime()` | 无参无返回值 | 输出 1~100 质数,每行 5 个(检查到 `Math.sqrt(n)`) |
| `printSum(int n, int m)` | 有参无返回值 | 输出 n~m 累加和 |
| `isPalindrome(int num)` | 有参有返回值 | 判断回文数(12321 / 12345 / 1221) |
| `getLuckyNumber()` | 无参有返回值 | Random 生成 1~100 幸运数字 |
### 题目 5:综合大挑战 — 学生成绩管理系统 ⭐⭐⭐⭐⭐
**知识点**:封装、对象数组、平均分、排序、查找
在包 `com.lovecoding.system` 下:`Student` 类(id/name/scores[3] + getAverage());`StudentSystem` 类(`initData()`、`printAll()`、`sortByAverage()` 降序、`searchByName()` 返回对象/null);`SystemTest` 测试类。
---
# 第 6 章 构造方法(07-21)
> **出处**:`课后作业/2026年7月21日-作业.md`、`课堂练习题/20260721-构造方法练习.md`
## 🎯 核心编程题
### 题目 1:构造方法 + 对象数组 — Movie 类 ⭐⭐⭐
**知识点**:私有属性、全参构造、对象数组、遍历找最值
`Movie` 类:`title`/`director`/`year`/`rating`,全参构造 + getter/setter + `showInfo()`。
测试:创建 `Movie[]` 数组存至少 4 部电影,**使用全参构造一次性初始化**(不用无参+setter),遍历输出评分最高的电影。
### 题目 2:构造方法 + Random — 猜数游戏(面向对象版)⭐⭐⭐⭐
**知识点**:构造方法初始化、Random、Scanner、循环
`GuessGame` 类:私有 `target`/`maxRange`/`attempts`;构造方法 `GuessGame(int maxRange)` 用 `nextInt(maxRange) + 1` 生成目标数字;`guess(int num)` 返回 `"猜对了!"/"大了,再小点"/"小了,再大点"` 并自增 attempts;测试类用 `while(true)` + Scanner 循环猜,猜对 break 输出总次数。
### 题目 3:构造方法 + 封装 + 排序 — BookManager ⭐⭐⭐⭐
**知识点**:全参构造、对象数组、冒泡排序、按名查找
`BookV2`(id/title/price 全参构造);`BookManager`:
- `initBooks()` — 无参有返回值,创建并返回 5 本图书数组
- `printBooks(BookV2[] books)` — 遍历输出
- `sortByPrice(BookV2[] books)` — 按价格从高到低冒泡排序
- `searchByTitle(BookV2[] books, String title)` — 用 `equals()` 查找,找不到返回 null
## ⭐ 重点编程题
### 题目 4:构造方法 + this() 调用 — Student 类 ⭐⭐⭐
**知识点**:this() 构造方法间调用(必须写在第一行)
无参构造调用全参构造传 `0, "未知", "未分配"`;`StudentV4(int id, String name)` 调用全参构造传默认班。
### 题目 5:综合大挑战 — MyArray 可变数组(动态数组底层实现)⭐⭐⭐⭐⭐
**知识点**:构造方法、数组扩容、增删改查、元素前移、冒泡排序
模仿 `ArrayList` 底层实现可变整型数组 `MyArray`(详见第 9 章重点题,内容相同)。
### 题目 6:综合大挑战 — 学生成绩管理系统(构造方法版)⭐⭐⭐⭐⭐
**知识点**:构造方法 + 封装 + 对象数组 + 排序
`StudentV5`(id/name/javaScore/mysqlScore + getAverage());`StudentSystem`(私有 `StudentV5[] students` + `count`,构造方法指定容量,`addStudent()` 满则提示、`printAll()`、`sortByAverage()`、`getTopStudent()` 返回最高分对象)。
---
# 第 7 章 继承(07-22)
> **出处**:`课后作业/2026年7月22日-作业.md`、`课堂练习题/20260722-继承练习.md`
## 🎯 核心编程题
### 题目 1:继承入门 — Appliance 电器体系 ⭐
**知识点**:继承的格式、子类调用父类方法
父类 `Appliance`(`powerOn()`/`powerOff()`),子类 `TV`(`changeChannel()`)、`WashingMachine`(`startWash()`)。观察子类直接使用父类方法,不需重复定义。
### 题目 2:继承 + 构造方法 + 方法重写 — Employee 员工体系 ⭐⭐
**知识点**:super() 调用父类构造、方法重写(Override)
父类 `Employee`(id/name/salary 全参构造 + `work()` 输出"员工在工作");子类 `Teacher`(新增 subject,`super(id,name,salary)`,重写 `work()` 输出"工号为xxx的xxx老师正在教授xxx课程")、`Doctor`(新增 specialty,重写 `work()`)。
> 子类构造方法第一行必须 `super(参数)`;重写的方法签名必须与父类完全一致;通过 `getId()`/`getName()` 获取父类私有属性。
## ⭐ 重点编程题
### 题目 3:多层继承 — Person → Student → Postgraduate ⭐⭐
**知识点**:多层继承、super()、方法重写
`Person`(name/age + showInfo)→ `Student`(+school,重写 showInfo)→ `Postgraduate`(+mentor,重写 showInfo),逐层 `super(...)` 调用父类构造。
### 题目 4:继承 + 对象数组 + 多态 — Employee 薪资管理系统 ⭐⭐⭐⭐
**知识点**:继承、构造方法 + super()、方法重写、多态、对象数组、冒泡排序
`Employee` 父类(id/name/baseSalary + `getSalary()` 返回基本工资 + `showInfo()`);子类 `Manager`(+bonus)、`Programmer`(+projectBonus)、`Designer`(+commission),**各自重写 `getSalary()`**。
测试:创建 `Employee[]` 数组混合存放不同类型员工,调用 `showInfo()` 观察多态,按 `getSalary()` 降序冒泡排序,查找薪资最高的员工。
### 题目 5:继承 + 抽象思想 — 图形面积计算器 ⭐⭐⭐⭐⭐
**知识点**:父类统一方法名、子类各自实现(抽象思想,不强制用 abstract)
`Shape`(color + `getArea()` 默认返回 0.0 + `showInfo()`);`Circle`/`Rectangle`/`Triangle` 重写 `getArea()`。创建 `Shape[]` 数组存储不同图形,按面积降序排序。
---
# 第 8 章 抽象类与接口(07-23)
> **出处**:`课后作业/2026年7月23日-作业.md`、`课堂练习题/20260723-抽象类与接口练习.md`
## 🎯 核心编程题
### 题目 1:抽象类 + 接口 — Printer 打印机体系 ⭐⭐
**知识点**:抽象类、接口、类同时继承抽象类并实现接口、方法重写、多态
- `Connectable` 接口:`connect()` / `print(String content)` / `close()`
- `Printer` 抽象类:私有 brand/model + 有参构造 + `showInfo()` + 抽象方法 `maintenance()`
- `LaserPrinter`(继承 Printer + 实现 Connectable,新增 tonerLevel)、`InkjetPrinter`(新增 inkLevel),重写全部抽象方法
```java
// 类同时继承抽象类并实现接口:extends Printer implements Connectable
public class LaserPrinter extends Printer implements Connectable { ... }
```
> **思考**:如果把 `Connectable` 改为抽象类让子类直接继承,会出现 Java 单继承限制的问题。
### 题目 2:接口 + JDK8 默认方法 — Notification 通知体系 ⭐⭐⭐
**知识点**:接口抽象方法、default 默认方法、static 静态方法、模拟模板方法
`Notifiable` 接口:
- 抽象方法 `doSend(recipient, message)`
- 默认方法 `validateParams()`(空值校验)、`log()`、`send()`(模板方法:校验 → doSend → log → 结束)
- 静态方法 `printNotificationType()`(必须通过 `接口名.方法名()` 调用)
`EmailNotifier`(重写 doSend + 可选重写 log)、`SMSNotifier`(重写 doSend,不重写默认方法)。
## ⭐ 重点编程题
### 题目 3:抽象类经典应用 — 模板方法设计模式(在线考试系统)⭐⭐⭐⭐⭐
**知识点**:抽象类、抽象方法、模板方法(`final`)、方法重写
`ExamTemplate` 抽象类:普通方法 `login()`/`deliverPaper()`/`announceResult()`,抽象方法 `conductExam()`/`gradeExam()`,**模板方法 `final void startExam()`** 按顺序执行完整流程。`JavaExam`/`MathExam` 子类只实现两个抽象方法。
> `startExam()` 用 `final` 修饰防止子类修改流程骨架。
### 题目 4:抽象类 + 多态 — 支付系统 Payment ⭐⭐⭐⭐⭐
**知识点**:抽象类、抽象方法重写、多态数组、统计
`Payment` 抽象类(amount/orderId + 抽象 `pay()`/`refund()` + 普通 `showPaymentInfo()`);`WeChatPay`/`AliPay`/`CreditCard` 子类各自重写。创建 `Payment[]` 数组遍历执行支付/退款,累加 `amount` 统计总金额。
---
# 第 9 章 多态(07-24)
> **出处**:`课后作业/2026年7月24日-作业.md`、`课堂练习题/20260724-多态练习.md`
## 🎯 核心编程题
### 题目 1:接口多态 + 转型 + instanceof — 智能家居控制系统 ⭐⭐⭐
**知识点**:接口多态(参数/数组)、向上转型、向下转型、instanceof、调用实现类特有方法、开闭原则
`SmartDevice` 接口(`turnOn()`/`doWork()`/`turnOff()`);实现类 `Light`(特有 `changeColor()`)、`AirConditioner`(特有 `setTimer()`)、`RobotVacuum`(特有 `startCleaningMode()`)。
```java
// 1. 创建 SmartDevice[] 数组装多种设备
SmartDevice[] devices = { new Light("客厅"), new AirConditioner("主卧", 26), ... };
// 2. 遍历执行通用流程 turnOn → doWork → turnOff
// 3. 遍历用 instanceof 判断后向下转型调用特有方法
if (device instanceof Light) {
((Light) device).changeColor("暖黄");
} else if (device instanceof AirConditioner) {
((AirConditioner) device).setTimer(4);
}
// 4. 封装静态方法 startDevice(SmartDevice device, int seconds)
```
> **思考**:新增 `SmartSpeaker` 实现类时控制器无需修改 —— 符合开闭原则;`instanceof` 判断的是运行时类型。
### 题目 2:MyArray 可变数组 — 动态数组底层实现 ⭐⭐⭐⭐⭐
**知识点**:构造方法、数组扩容(1.5 倍)、增删改查、元素前移、冒泡排序
模仿 `ArrayList` 底层实现(核心 11 个方法):
- `add(int element)` — 满则扩容为 `data.length * 3 / 2`,扩容三步(建新数组→复制→替换引用)
- `get/set/size/capacity/isEmpty/indexOf/contains`
- `remove(int index)` — 后面元素前移一位、size--、返回被删值
- `removeByValue(int element)` — 调 indexOf + remove
- `sort(boolean ascending)` — 冒泡排序只对 `data[0]~data[size-1]`
### 题目 3:模板方法设计模式 — 在线考试系统 ⭐⭐⭐⭐⭐
**知识点**:抽象类、模板方法(`final`)、方法重写
(同第 8 章重点题 3,父类定义骨架、子类实现步骤。)
## ⭐ 重点编程题
### 题目 4:多态 + 对象数组 + instanceof — 员工绩效管理系统 ⭐⭐⭐⭐
**知识点**:多态数组、instanceof 向下转型、调用特有方法、薪资统计
`Employee` 抽象类(id/name + 抽象 `calculateSalary()` + 普通 `showInfo()`);`FullTimeEmployee`(baseSalary+bonus×1.2)、`PartTimeEmployee`(时薪×工时)、`Intern`(固定津贴),各有特有方法。遍历数组按 `instanceof` 转型调用特有方法,计算总薪资、找最高薪。
### 题目 5:综合应用 — Usb 设备管理器(接口多态 + instanceof)⭐⭐⭐⭐⭐
**知识点**:接口多态、Usb 数组、instanceof、开闭原则
`Usb` 接口(`startUsb()`/`stopUsb()`);`Mouse`/`Keyboard`/`USBHub` 实现类各有特有方法;`NoteBook` 类持 `Usb[]` 数组 + `plugIn()` + `workAll()`(遍历执行 start → instanceof 转型调特有方法 → stop)。
---
# 第 10 章 匿名内部类与 JavaAPI(07-27)
> **出处**:`课后作业/2026年7月27日-作业.md`、`课堂练习题/20260727-内部类练习.md`
## 🎯 核心编程题
### 题目 1:匿名内部类 — 支付系统 ⭐⭐⭐
**知识点**:匿名内部类三种使用方式(变量赋值 / 方法参数传递 / 匿名对象直接调用)
`Payment` 接口(`pay()`/`refund()`);`OrderService.processPayment(Payment payment, double amount)` 业务类。
1. **变量赋值**:`Payment wechat = new Payment() { ... };` 实现微信支付
2. **方法参数**:`service.processPayment(new Payment() { ... }, 299.0);` 支付宝
3. **匿名对象直接调用**:在匿名内部类中定义特有方法 `showBonus()`,通过 `new Payment(){...}.showBonus()` 直接调用
4. **选做**:创建 `Object` 的匿名内部类子类重写 `toString()`
### 题目 2:String + StringBuilder — 字符串处理工具 ⭐⭐
**知识点**:split / substring / contains / replace / trim / equalsIgnoreCase / StringBuilder.append
1. **去重统计**:`data` 按逗号分割 + `trim()` 去空格 + 统计每个姓名出现次数
2. **关键词搜索**:`contains()` / `indexOf()` / `startsWith()` / `endsWith()`
3. **子串提取 + 替换**:`substring()` 提取前三个姓名 + `replace()` 替换
4. **StringBuilder 拼接(核心)**:从 `names` split 出每个姓名,用 `append()` 逐条拼接生成 HTML `
` 列表
5. **String.join**:`String.join(" | ", 数组)` 拼接
### 题目 3:Math + 日期时间 — 数据分析小工具 ⭐⭐
**知识点**:Math(PI/pow/sqrt/ceil/floor/round/random/abs/max/min)、LocalDate / LocalTime / LocalDateTime / DateTimeFormatter
- **Math**:圆面积周长、2¹⁰、√16、最高/最低分、平均分取整(ceil/floor/round)、`Math.random()` 生成 6 位验证码、`abs()` 求温差
- **日期时间**:`LocalDate.now()/of()`、`until()` 计算天数差、日期加减 100 天、`LocalTime.now()/of()`、`DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分ss秒")` 格式化
- **综合**:生成随机日期并判断星期几
## ⭐ 重点编程题
### 题目 4:内部类综合 — 学生信息管理系统(匿名内部类 + 排序 + 筛选 + 接口回调)⭐⭐⭐⭐⭐
**知识点**:匿名内部类作为方法参数(策略模式雏形)、自定义 Comparator/Filter 接口、冒泡排序
`StudentManager`:`sortStudents(Student[], Comparator)` / `filterStudents(Student[], Filter)` / `findMax(Student[], Comparator)`,全部用**匿名内部类**传参。6 个任务:按成绩降序、按年龄升序、按姓名长度排序、筛选成绩≥85、筛选年龄>20、查找成绩最高。
> 体会"行为参数化"思想 —— 排序/筛选逻辑作为参数传入方法。
### 题目 5:内部类综合 — 银行账户系统(私有内部类 + 局部内部类 + 静态内部类)⭐⭐⭐⭐⭐
**知识点**:私有内部类(外界不可见,通过 Bank 公共方法操作)、局部内部类(方法内定义)、静态内部类(RateInfo 共享利率)
`Bank` 类:私有成员内部类 `Account`(含局部内部类 `DepositTransaction`/`WithdrawTransaction`)、静态内部类 `RateInfo`(静态常量 SAVING_RATE/LOAN_RATE + `calculateInterest()` 复利计算)。
---
# 第 11 章 异常处理(07-28)
> **出处**:`课堂练习题/20260728-异常处理练习.md`
## 🎯 核心编程题
### 题目 1:异常处理的鲁棒性 — 学生成绩处理系统 ⭐⭐⭐
**知识点**:try-catch-finally 综合运用、多异常场景
`ScoreManager.sum(Double[] scores)`:null 数组返回 0、空数组返回 0、null 元素跳过继续累加。`average()` 中调用 sum() 计算有效成绩个数,用 try-catch 包裹整个方法捕获任意异常。
### 题目 2:throw 关键字 — 手动抛出异常 ⭐⭐
**知识点**:throw、业务逻辑校验
四个任务:`setAge()` 年龄 0~130 否则抛 `IllegalArgumentException`;`withdraw()` 金额≤0 或超余额抛异常;`parseInt()` 空串/非数字字符手动抛 `NumberFormatException`;验证 throw 后代码不执行(不可达语句)。
## ⭐ 重点编程题
### 题目 3:用户注册验证系统(自定义异常 + 多 catch)⭐⭐⭐⭐
**知识点**:自定义异常(继承 Exception)、throws 声明、多 catch、finally 操作日志
定义 `UsernameEmptyException` / `UsernameLengthException` / `PasswordEmptyException` / `PasswordWeakException` / `AgeInvalidException`。`RegisterService.register()` 用 try-catch-finally 依次验证用户名→密码→年龄,每个验证独立 catch 输出错误提示,**finally 输出操作日志**。
### 题目 4:银行 ATM 取款系统(异常处理 + 封装 + 业务逻辑)⭐⭐⭐⭐⭐
**知识点**:自定义业务异常、异常向上抛出、多 catch、finally 交易记录
`Account.withdraw()` **把异常抛给调用者**(`throws InvalidAmountException, WithdrawLimitExceededException, InsufficientBalanceException`);`ATM.withdraw()` 用多 catch 分别处理,**finally 输出【交易记录】**。
> 思考:`findAccount()` 返回 null vs 抛 `AccountNotFoundException` 的优缺点;finally 保证交易记录一定输出。
### 题目 5:商品库存管理系统(throw + throws + 编译期 vs 运行时异常对比)⭐⭐⭐⭐
**知识点**:编译期异常(继承 Exception)vs 运行时异常(继承 RuntimeException)
`setPrice()` 抛 `InvalidPriceException`(RuntimeException,无需 throws);`findProduct()` 抛 `ProductNotFoundException`(Exception,必须 throws)。`outbound()` 用 **try-finally**(不处理异常、只保证资源关闭);`inbound()` 用 **try-catch-finally**(内部处理 + 关闭)。
### 题目 6:finally 专项练习 — 文件读取模拟器 ⭐⭐⭐⭐
**知识点**:try-finally、try-catch-finally、finally 与 return 执行顺序、finally 修改返回值、finally 中的异常传播
6 个任务验证:
1. 基本 try-finally(异常仍关闭文件)
2. finally 在 return **之前**执行,但返回值不变
3. finally 修改局部变量不影响已 return 的基本类型值
4. finally 中抛异常会**覆盖** try 中异常
5. try-catch-finally 资源释放计数
6. catch 中 return 后 finally 依然执行
---
# 第 12 章 集合框架(ArrayList)(07-29)
> **出处**:`课后作业/2026年7月29日-作业.md`、`课堂练习题/20260729-集合框架练习.md`
## 🎯 核心编程题
### 题目 1:学生信息录入系统 ⭐
**知识点**:ArrayList 创建、add()、size()、for+get 遍历、包装类
`Student` 类(name / **Integer age(包装类)** / studentId),创建 `ArrayList` 存储 4 个学生并遍历输出。
### 题目 2:学生信息维护 — 增删改查 ⭐⭐
**知识点**:`isEmpty()` / `set()` / `remove(index)` / `add(index, element)` / 遍历查找
判断是否为空 → 遍历查找学号 S003 → `set()` 改名 → `remove()` 删除 → `add(1, 新学生)` 指定索引插入 → 再次遍历输出。
### 题目 3:学生年龄统计与分析 ⭐⭐
**知识点**:遍历、条件筛选、包装类自动拆箱、冒泡排序
计算平均年龄(Integer 自动拆箱)、统计 ≥20 岁学生、找年龄最大、按年龄冒泡排序。
## ⭐ 重点编程题
### 题目 4:ArrayList 源码注释分析(构造 / 扩容 / 增删改)⭐⭐⭐⭐⭐
**知识点**:ArrayList 底层原理、扩容机制、fail-fast(modCount)、System.arraycopy
逐行注释分析源码并回答思考题:
- **构造方法**:`EMPTY_ELEMENTDATA` vs `DEFAULTCAPACITY_EMPTY_ELEMENTDATA` 的区别(懒加载优化)
- **扩容**:`grow()` 中 `ArraysSupport.newLength(oldCapacity, minGrowth, oldCapacity >> 1)`(1.5 倍扩容)、`trimToSize()`、`ensureCapacity()`
- **增删**:`fastRemove()` 中 `System.arraycopy` 前移、删除后末位置 null、`clear()` 遍历置 null vs 直接换空数组
- **选做加分**:手写泛型简化版 `MyArrayList`(无参默认容量 10、自动扩容、CRUD、toString)
### 题目 5:进阶综合 — 教室座位管理系统 ⭐⭐⭐⭐
**知识点**:`ArrayList>` 嵌套模拟二维结构
`Classroom` 类:`seats` 为 4 排 × 5 列(初始全 null),`assignSeat(row, col, student)`(越界检查 + 占用检查)、`displaySeats()`、`countEmptySeats()`、`countOccupiedInRow(row)`。
---
# 第 13 章 LinkedList 与双链表(07-30)
> **出处**:`课后作业/2026年7月30日-作业.md`、`课堂练习题/20260730-LinkedList双链表练习.md`
## 🎯 核心编程题
### 题目 1:银行叫号系统 — Queue 队列操作 ⭐
**知识点**:`offer()` / `poll()` / `peek()`、FIFO 特性
用 `Queue queue = new LinkedList<>()` 模拟叫号:客户 A/B/C 依次 offer 入队 → peek 看队首 → poll 叫号出队 → 新客户 D 入队 → 再次 poll → 输出剩余。**空队列 poll()/peek() 返回 null 不抛异常**。
```java
Queue queue = new LinkedList<>();
queue.offer("客户A"); queue.offer("客户B"); queue.offer("客户C");
System.out.println("请" + queue.poll() + "前往1号窗口"); // 请客户A前往1号窗口
```
### 题目 2:浏览器后退功能 — Stack 栈操作 ⭐
**知识点**:`push()` / `pop()` / `peek()`、LIFO 特性、`Deque` 接口栈语义
用 `Deque stack = new LinkedList<>()` 模拟浏览器后退:push 访问页面 → peek 看栈顶 → pop 后退 3 次 → 循环 pop 清空。**空栈 pop() 抛 `NoSuchElementException`**(与 Queue 的 poll() 不同)。
> Java 官方建议用 `Deque` 代替 `Stack` 类(Stack 继承 Vector,性能差且不必要的线程安全开销)。
### 题目 3:LinkedList 基本操作(List 角色)⭐
**知识点**:add / get / set / remove(index) / add(index, element)
## ⭐ 重点编程题
### 题目 4:LinkedList 与 ArrayList 性能对比实验 ⭐⭐⭐
**知识点**:时间复杂度、`add(index)` 头部插入、`get(index)` 随机访问、遍历方式
四个实验对比耗时(`System.currentTimeMillis()`):
1. 尾部添加(相近)
2. 头部插入 10000 次(**LinkedList O(1) 远快于 ArrayList O(n)**)
3. 随机访问 100000 次(**ArrayList O(1) 远快于 LinkedList O(n)**)
4. for+get 遍历(**LinkedList O(n²) 极慢**,应用 foreach / 迭代器)
### 题目 5:手写单链表 — 完善 MyLinked 类 ⭐⭐⭐⭐
**知识点**:链表数据结构、泛型、Node 节点、增删改查
补全 `MyLinked`:`get(index)`(检查越界 + 从头遍历)、`remove(index)`(找到前驱节点 prevNode,`prevNode.next = target.next`,删尾节点更新 lastNode)、`contains(value)`(考虑 null)、`toArray()`(`(N[]) new Object[size]` 泛型擦除强转)、`clear()`(断开头节点引用)。
---
# 第 14 章 Map 与迭代器(07-31)
> **出处**:`课后作业/2026年7月31日-作业.md`、`课堂练习题/20260731-迭代器与Map集合练习.md`
## 🎯 核心编程题
### 题目 1:Iterator 迭代器遍历 ⭐
**知识点**:`iterator()` / `hasNext()` / `next()`、for+get vs 迭代器
用 for+get 遍历 ArrayList,再用迭代器统一遍历 ArrayList 和 LinkedList。**LinkedList 用 for+get 遍历 O(n²),迭代器是最佳方式**。
### 题目 2:HashMap 基本操作 — 学生成绩表 ⭐⭐
**知识点**:put / get / containsKey / remove / keySet / entrySet、键不可重复
创建 `HashMap`(学号→成绩),测试 size、get、containsKey、put 覆盖旧值、remove,并用**两种方式遍历**:① keySet + foreach + get(key);② entrySet + foreach + getKey()/getValue()。创建 `TreeMap` 观察按键自动排序。
### 题目 3:HashSet 与 TreeSet — 单词去重与排序 ⭐⭐
**知识点**:HashSet 去重(无序)、TreeSet 自动排序(字典序/数值升序)
## ⭐ 重点编程题
### 题目 4:自定义类作为 HashMap 的 Key(重写 hashCode / equals)⭐⭐⭐
**知识点**:HashMap 键唯一性依赖 hashCode 定位 + equals 比较
`Student` 重写 `hashCode()`(`Objects.hash(id, name)`)和 `equals()`。验证:两个属性相同的 Student 对象 equals 为 true、哈希值相同、作为 Key 存入 Map 后 `map.size() == 1`,用属性相同的新对象 get 也能查到。
> **原理**:不重写时默认 hashCode 基于对象地址 → 两个 new 对象哈希不同 → size=2;先 hashCode 定位,位置有元素再用 equals 比较。
### 题目 5:单词词频统计器 ⭐⭐⭐⭐
**知识点**:Map 键值对建模、put / get / containsKey、getOrDefault
```java
Map map = new HashMap<>();
for (String word : words) {
if (map.containsKey(word)) map.put(word, map.get(word) + 1);
else map.put(word, 1);
}
// 简化:map.put(word, map.getOrDefault(word, 0) + 1);
// 遍历 entrySet 找出现次数最多的单词
```
### 题目 6:学生排序系统(匿名内部类 + 集合排序)⭐⭐
**知识点**:匿名内部类实现 Comparator、`Collections.sort()`、TreeSet 自定义排序
`Student`(name/age/score);`SortDemo`:匿名内部类 Comparator 按年龄升序、按成绩降序(`Double.compare`),TreeSet 传入按姓名排序的匿名 Comparator。
> **必做简答题**:HashMap 底层原理(数组+链表/红黑树、树化条件 >8 且容量 >64、退化 <6、默认容量 16 负载因子 0.75)。
---
# 第 15 章 比较器排序与可变参数(08-03)
> **出处**:`课后作业/2026年8月3日-作业.md`、`课堂练习题/20260803-比较器排序练习.md`
## 🎯 核心编程题
### 题目 1:Comparable 自然排序 — 学生成绩排行榜 ⭐
**知识点**:Comparable、compareTo 重写、二次比较、TreeSet 自动排序+去重
`Student implements Comparable`,**按成绩降序,成绩相同再按姓名**:
```java
@Override
public int compareTo(Student o) {
int result = Double.compare(o.getScore(), this.score); // 成绩降序
return result == 0 ? this.name.compareTo(o.getName()) : result; // 二次比较
}
```
> 返回值规则:负数存左 / 0 重复不存 / 正数存右。张三和赵六同分但姓名不同 → compareTo 不为 0 → 都能存入。
### 题目 2:Comparator 比较器排序 + Collections 工具类 — 商品价格排序 ⭐⭐
**知识点**:Collections.sort(list, comparator)、匿名内部类、Double.compare、降序技巧
`Product`(name/price/stock)**不实现** Comparable。用匿名内部类 Comparator 按价格升序 / 降序(**交换参数位置**)/ 按库存升序;再用 `Collections.max/min(list, comparator)` 找最高/最低价。
> double 不能用 `(int)(p1.getPrice() - p2.getPrice())`(浮点精度+强转截断),必须用 `Double.compare`。
### 题目 3:可变参数 Varargs ⭐⭐
**知识点**:`int... a`、for each、可变参数本质即数组、可变参数置末
```java
public int add(int... a) { // 本质就是 int[] a
int sum = 0;
for (int n : a) sum += n;
return sum;
}
// 固定参数 + 可变参数(可变参数必须放最后)
public void showScore(String name, int... scores) { ... }
```
## ⭐ 重点编程题
### 题目 4:Lambda 表达式 — 简化接口实现与排序 ⭐⭐
**知识点**:函数式接口、Lambda 标准格式、三条省略规则
```java
useAdd((a, b) -> a + b); // 单语句省略大括号、分号、return
useFlyable(s -> { ... }); // 单参数省略小括号
Collections.sort(list, (s1, s2) -> Double.compare(s2.getScore(), s1.getScore()));
```
### 题目 5:综合应用 — 员工信息管理系统 ⭐⭐
**知识点**:Comparable 自然排序 + equals/hashCode 一致性 + TreeSet 去重 + Comparator 按姓名排序
`Employee`(id/name/salary/dept):compareTo 按薪资降序、薪资相同按工号;equals/hashCode **以工号判定**(与 compareTo 口径一致 → 工号相同的自动去重);临时按姓名排序用匿名内部类/Lambda(不改 Employee 类)。
> **原理**:E002 添加两次只存一个,因 compareTo 工号相同返回 0 视为重复;compareTo == 0 → equals 返回 true、hashCode 一致(官方推荐)。
### 题目 6:进阶 — 成绩排行榜(TreeMap + Comparable 键排序)⭐⭐⭐
**知识点**:TreeMap 按键排序、自定义类型作为 Key
把 Student 作为 **Key**、班级作为 Value 存入 `TreeMap`,按 compareTo 规则自动排序。
---
# 第 16 章 Stream 流与函数式编程(08-04)
> **出处**:`课堂练习题/20260804-Stream流练习.md`、`课后作业/2026年8月4日-作业.md`(期末综合大作业)
## 🎯 核心编程题
### 题目 1:生成 Stream 流的四种方式 ⭐
**知识点**:`Collection.stream()` / Map 转 Set / `Arrays.stream()` / `Stream.of()`
```java
List list = ...; list.stream();
map.keySet().stream(); map.values().stream();
Arrays.stream(array);
Stream.of("长贵", "赵四", "刘能");
```
### 题目 2:filter 过滤 + forEach 遍历 ⭐⭐
**知识点**:filter(Predicate)、forEach(Consumer)、方法引用
```java
list.stream().filter(s -> s.startsWith("万")).forEach(System.out::println);
// 叠加过滤:filter(s -> s.length() == 3)
// 统计:long count = list.stream().filter(...).filter(...).count();
```
### 题目 3:中间方法链式调用 — filter / limit / skip(分页)⭐⭐
**知识点**:limit、skip、分页思想
```java
// 分页通用公式:skip((pageNo-1)*pageSize).limit(pageSize)
Stream.of(0,1,2,3,4,5,6,7,8,9).skip((pageNo-1)*pageSize).limit(pageSize).forEach(...)
```
### 题目 4:concat 合并两流 + distinct 去重 ⭐⭐
**知识点**:`Stream.concat(a, b)`(静态方法)、`distinct()`(依据 equals)
### 题目 5:终结操作 — count 计数 + forEach 遍历 ⭐⭐
**知识点**:终结方法只能有一个、`count()` 返回 long
```java
list.stream().forEach(System.out::println).count(); // 编译报错!终结方法后流已结束
```
### 题目 6:collect 收集操作 ⭐⭐⭐
**知识点**:`Collectors.toList()` / `toSet()`
```java
List l = list.stream().distinct().collect(Collectors.toList());
Set s = list.stream().filter(x -> x.contains("伊")).collect(Collectors.toSet());
// toList() 返回不可变集合,add 抛 UnsupportedOperationException
```
## ⭐ 重点编程题
### 题目 7:Collectors.toMap 收集成 Map ⭐⭐⭐⭐
**知识点**:`toMap(keyMapper, valueMapper)`、Function 函数式接口、Lambda vs 匿名内部类
```java
Map map = list.stream()
.collect(Collectors.toMap(student -> student.getId(), student -> student));
// 匿名内部类等价写法:new Function() { apply(...) }
// 键重复默认抛 IllegalStateException
```
### 题目 8:综合实战 — 员工信息流式处理 ⭐⭐⭐⭐
**知识点**:filter / distinct / count / collect / toMap 综合、方法引用
```java
list.stream().filter(e -> "技术部".equals(e.getDept())).forEach(System.out::println);
list.stream().map(Employee::getName).distinct().forEach(System.out::println); // 按姓名去重
long cnt = list.stream().filter(e -> "技术部".equals(e.getDept())).count();
Map map = list.stream().collect(Collectors.toMap(Employee::getId, Employee::getName));
```
### 题目 9:期末综合大作业 — 学生信息管理系统(JavaSE 收官之作)⭐⭐⭐⭐
**知识点**:贯穿整个 JavaSE(封装/继承/抽象类/接口/异常/集合/比较器/多态)+ 模块五 Stream 选做
按模块分层:
- **模块一**(entity 包):`Person` 抽象类(name/age + 抽象 `getRole()`)、`Studyable`/`Teachable` 接口、`Student extends Person implements Comparable, Studyable`(学号 id/班级/成绩列表,compareTo 按平均分降序二次比较学号,equals/hashCode 以学号判定)、`Teacher`、`Course`、`Score`
- **模块二**(exception 包):4 个自定义异常(继承 Exception):`ScoreOutOfBoundsException` / `StudentNotFoundException` / `CourseNotFoundException` / `DuplicateStudentException`
- **模块三**(manager 包 + main):`StudentManager`(增删改查,重复学号抛异常,`findById` 用迭代器)、`CourseManager`、`ScoreManager`(`HashMap>` 按学号分组)、`StudentSystemApp`(Scanner + switch + while 主菜单,try-catch 处理自定义异常)
- **模块四**(util 包):`RankUtil` 四个排序(TreeSet 自然排序排行榜 / Comparator 按姓名 / Lambda 按年龄 / 按平均分降序)
- **模块五**(选做):`StreamQuery` 六个 Stream 查询(filter/map/count/distinct/toMap/sorted)
---
# 第 17 章 File 与 IO 流(08-06)
> **出处**:`课后作业/2026年8月6日-作业.md`、`课堂练习题/20260806-File文件操作练习.md`
## 🎯 核心编程题
### 题目 1:文件复制器 FileCopy ⭐⭐⭐
**知识点**:`FileInputStream` / `FileOutputStream`、`read(byte[])` / `write(byte[], 0, len)`、缓冲区 `byte[4096]`、`-1` 判断、close、耗时统计
```java
FileInputStream fis = new FileInputStream(src);
FileOutputStream fos = new FileOutputStream(desc);
byte[] bytes = new byte[4096];
int length;
long start = System.currentTimeMillis();
while ((length = fis.read(bytes)) != -1) { // -1 表示读完
fos.write(bytes, 0, length); // 只写本次有效字节
}
fos.close(); fis.close(); // 先关输出再关输入
long end = System.currentTimeMillis();
System.out.println("复制完成!耗时:" + (end - start) + " 毫秒");
```
> **关键**:`fis.read(bytes)` 返回本次有效长度,可能小于缓冲区大小,写入必须用 `write(bytes, 0, length)` 截断,否则文件变大。
### 题目 2:文件管理器(File 常用操作)⭐⭐⭐
**知识点**:`new File(String)`、`mkdir` / `mkdirs`、`createNewFile`、`delete`、`isFile` / `isDirectory` / `exists`、`getName` / `getPath` / `getAbsolutePath` / `listFiles`
> `mkdir()` 单级创建(父目录不存在返回 false);`mkdirs()` 多级创建更推荐;`createNewFile()` 编译期异常需处理;`delete()` 删非空目录返回 false;`listFiles()` 返回 `File[]`。
---
# 第 18 章 IO 缓冲流与字符流(08-07)
> **出处**:`课后作业/2026年8月7日-作业.md`、`课堂练习题/20260807-IO缓冲流练习.md`
## 🎯 核心编程题
### 题目 1:字符流中文读写器 CharFileDemo ⭐⭐
**知识点**:字符流 = 字节流 + 字符集编码表、`FileWriter.write(String)` 直接写中文、`FileReader.read(char[])`、`new String(chars, 0, count)`
```java
// 写:FileWriter 直接写中文(无需 getBytes)
FileWriter fw = new FileWriter("D:/poem.txt");
fw.write("床前明月光,疑是地上霜。"); fw.write("\r\n");
fw.write("举头望明月,低头思故乡。");
fw.flush(); fw.close();
// 读:read(char[]) 批量读取
FileReader fr = new FileReader("D:/poem.txt");
char[] chars = new char[1024];
int count;
while ((count = fr.read(chars)) != -1) {
System.out.print(new String(chars, 0, count)); // 只取有效部分
}
fr.close();
```
### 题目 2:字符缓冲流成绩排序写回 ScoreSort ⭐⭐⭐
**知识点**:`BufferedReader` / `BufferedWriter`、`readLine()` 逐行读取、`newLine()` 换行、`split("-")`、`Integer.parseInt()`、ArrayList + Collections.sort
读 `D:/scores.txt`("姓名-成绩"顺序乱)→ 五步闭环:读取 → 处理(split+parseInt)→ 集合(封装 Student)→ 排序(按成绩降序)→ 写回(带名次)。
```java
BufferedReader br = new BufferedReader(new FileReader("D:/scores.txt"));
ArrayList list = new ArrayList<>();
String line;
while ((line = br.readLine()) != null) {
String[] parts = line.split("-");
list.add(new Student(parts[0], Integer.parseInt(parts[1])));
}
Collections.sort(list, (o1, o2) -> o2.getScore() - o1.getScore()); // 成绩降序
BufferedWriter bw = new BufferedWriter(new FileWriter("D:/sorted.txt"));
for (int i = 0; i < list.size(); i++) {
bw.write("第" + (i+1) + "名:" + list.get(i));
bw.newLine(); // 跨平台换行
}
bw.flush(); bw.close(); br.close();
```
## ⭐ 重点编程题
### 题目 3:接口化文件复制效率对比器 CopyCompare ⭐⭐⭐⭐
**知识点**:`CopyFile` 接口(面向接口编程/多态)、普通字节流 vs 缓冲流、try-catch-finally、耗时对比
`CopyFile` 接口 `String copy(String src, String desc) throws IOException`;`Copy01`(普通字节流 + byte[8192] + try-catch-finally)、`BufferedCopy`(`BufferedOutputStream` 包装底层流)。复制同一大文件对比耗时,验证"缓冲流更快"。
> 关闭顺序:`Copy01` 先关 fos 再关 fis;`BufferedCopy` 先关缓冲流再关底层流。
### 题目 4:字符集(Charset)与乱码实验 ⭐⭐⭐⭐
**知识点**:`Charset.forName("GBK")`、`FileWriter(String, Charset)` / `FileReader(String, Charset)`、编码/解码、乱码原理
用 GBK 写入中文 → 默认字符集(UTF-8)读 → 乱码;改用 GBK 读 → 正常。一个汉字 GBK 占 2 字节、UTF-8 占 3 字节。
```java
FileWriter fw = new FileWriter("D:/编码.txt", Charset.forName("GBK"));
FileReader fr = new FileReader("D:/编码.txt", Charset.forName("GBK")); // 指定同一字符集
```
### 题目 5:用户信息永久化存储(Scanner + FileWriter)⭐⭐⭐
**知识点**:Scanner 键盘录入、FileWriter 写入、数据持久化
录入用户名密码写入 `D:/user.txt`;选做升级:追加模式 `new FileWriter(path, true)` 多用户注册、FileReader 读取做登录校验。
---
# 第 19 章 对象序列化与多线程(08-08)
> **出处**:`课堂练习题/20260808-对象序列化与转换流练习.md`、`课后作业/2026年8月8日-作业.md`
## 🎯 核心编程题
### 题目 1:多个学生对象序列化与反序列化 ⭐⭐⭐⭐
**知识点**:`Serializable` 标记接口、`ObjectOutputStream.writeObject()` / `ObjectInputStream.readObject()`、集合也是对象
`Student implements Serializable` + `serialVersionUID`。把 3 个学生装进 `ArrayList`,**整个集合一次性序列化**,再一次性反序列化读回强转遍历。
```java
class Student implements Serializable {
private static final long serialVersionUID = 42L; // 固定版本号
private Integer id; private String name; private Integer age;
// ...
}
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:/students.txt"));
oos.writeObject(list); oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:/students.txt"));
ArrayList readList = (ArrayList) ois.readObject(); // Object 需强转
```
### 题目 2:transient 与 serialVersionUID 验证 ⭐⭐⭐⭐
**知识点**:`transient` 不参与序列化、`InvalidClassException`、类版本兼容
- `transient Integer id` 序列化后读回为 **null**
- 去掉 serialVersionUID 修改类结构 → 反序列化抛 `InvalidClassException`(JVM 自动版本号变化)
- 加上固定 `serialVersionUID = 42L` → 类结构变化也能读(缺失属性赋默认值)
### 题目 3:多线程实现方式一 — 继承 Thread 求和 ⭐⭐
**知识点**:`extends Thread`、重写 `run()`、`super(name)`、`start()`、run vs start
`SumThread extends Thread`,`super(name)` 传线程名,run() 中 1~100 边加边打印 `this.getName() + "--->" + i`,结束打印求和结果(5050)。main 中创建两个线程 `start()` 观察输出交错。
> 直接调 `run()` 不创建新线程,只是普通方法调用 —— 验证 run 与 start 的区别。
### 题目 4:多线程实现方式二 — 实现 Runnable 三种方式 ⭐⭐⭐
**知识点**:`implements Runnable`、`Thread.currentThread().getName()`、`Thread(Runnable, name)`、实现类对象/匿名内部类/Lambda
```java
// 三种提供任务方式:
new Thread(new CountTask(), "任务线程"); // ① 实现类对象
new Thread(new Runnable(){ public void run(){...} }, "匿名线程"); // ② 匿名内部类
new Thread(() -> { ... }, "Lambda线程"); // ③ Lambda(Runnable 是函数式接口)
// main 主线程也循环打印,观察 4 种线程名交错(主线程与子线程并发,start() 不阻塞)
```
## ⭐ 重点编程题
### 题目 5:多线程实现方式三 — Callable + FutureTask 带返回值 ⭐⭐⭐⭐
**知识点**:`Callable`(call() 带返回值)、`FutureTask` 包装、`get()` 阻塞获取
`SumCallable implements Callable` 求 1~n 的和并 `return sum`;用 `FutureTask` 包装后 `new Thread(futureTask, "线程名").start()`;`ft.get()` 阻塞等待取回每个线程结果,main 中汇总。
> 三种方式对比:run() 无返回值 vs call() 有返回值;实现接口 vs 继承类。
### 题目 6:转换流字符集转码(UTF-8 → GBK)⭐⭐⭐
**知识点**:`InputStreamReader` / `OutputStreamWriter` 转码、编码/解码
```java
InputStreamReader isr = new InputStreamReader(new FileInputStream("D:/abc.txt"), "UTF-8");
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:/hello.txt"), "GBK");
char[] chars = new char[1024]; int count;
while ((count = isr.read(chars)) != -1) { osw.write(chars, 0, count); }
osw.close(); isr.close();
```
> 转换流是"扩展流(处理流)":不直接操作文件,包装底层字节流增加转码能力;读端指定源字符集、写端指定目标字符集。
---
# 第 20 章 多线程进阶(08-10)
> **出处**:`课后作业/2026年8月10日-作业.md`、`课堂练习题/20260810-线程操作与生命周期练习.md`
## 🎯 核心编程题
### 题目 1:线程优先级 + 生命周期观察赛跑 ⭐⭐
**知识点**:`setPriority()` / `getPriority()`、`Thread.MAX/NORM/MIN_PRIORITY`、`Thread.State` 6 种状态、`getState()`、`join()`
用 Lambda 创建 Runnable 运动员任务(3 个线程优先级 10/5/1),每圈 sleep(100) 模拟跑步,用 `getState()` 观察 **NEW → RUNNABLE → TIMED_WAITING → TERMINATED** 状态流转,最后 `t1.join()` 等待。
> 优先级只是提高获得 CPU 的**概率**,不保证先执行完(抢占式调度 + 随机性)。
### 题目 2:守护线程后台心跳监控 ⭐⭐⭐
**知识点**:`setDaemon(true)` / `isDaemon()`、JVM 退出机制、守护线程特点
用户线程"主任务"执行 5 秒业务 + 守护线程"心跳监控"每 500ms 报一次心跳。**`heart.setDaemon(true)` 必须在 `start()` 之前**;`task.join()` 等主任务结束;main 结束后只剩守护线程 → JVM 退出 → 心跳被强制终止。
> JVM 退出条件:所有用户线程结束才退出;守护线程被强杀时 finally 不保证执行。
### 题目 3:synchronized 线程同步 — 修复卖票问题 ⭐⭐⭐⭐
**知识点**:线程安全问题(数据竞争)、读-改-写复合操作、synchronized 三种写法、线程安全三大特性
3 个窗口线程卖 100 张票。**先不加锁复现 Bug**(相同票多次出现 + 负数票),再用 synchronized 修复:
1. **同步方法**:`public synchronized void sell()`(锁 this)
2. **同步代码块锁自定义对象**:`synchronized(lock) { ... }`
3. 同步静态方法锁 Class 对象(选做)
> Bug 原因:`if (tickets > 0)` 判断与 `tickets--` 修改之间是读-改-写复合操作,可能被并发打断;锁对象必须一致(共用同一个 SellTicket 对象)。
## ⭐ 重点编程题
### 题目 4:线程生命周期观察 — getState() 打印 6 种状态 ⭐⭐⭐
**知识点**:`Thread.State` 枚举、NEW / RUNNABLE / TIMED_WAITING / TERMINATED
在 start() 前(NEW)、start() 后(RUNNABLE)、sleep 期间(TIMED_WAITING)、join 结束后(TERMINATED)分别打印状态。
### 题目 5:join + interrupt + yield — 主线程协作等待 ⭐⭐⭐⭐
**知识点**:`join()` / `join(long)`、`interrupt()` / `isInterrupted()` 中断标志、catch 后重设标志、`yield()`
- worker-1 循环中 `yield()` 让出 CPU + sleep(200),主线程 `join()` 等它结束
- worker-2 sleep(5000) 长任务,主线程 sleep(500) 后 `interrupt()` 中断,catch 中 **`Thread.currentThread().interrupt()` 重设中断标志**
> `interrupt()` 不会杀线程,只是设置中断标志请求线程自行响应;`InterruptedException` 抛出时标志被清除。
---
# 第 21 章 volatile 与 Lock 锁(08-11)
> **出处**:`课后作业/2026年8月11日-作业.md`、`课堂练习题/20260811-volatile与Lock锁练习.md`
## 🎯 核心编程题
### 题目 1:volatile 可见性 — "程序永不退出"复现与修复 ⭐⭐⭐
**知识点**:JVM 内存模型(工作内存 CPU 缓存 vs 主内存)、`volatile` 三大语义、方法引用创建线程
`private volatile boolean running = true;`;`work()` 中 `while(running)` 空循环,main 线程 sleep 后 `stop()` 修改 running。
- 不加 volatile → worker 读缓存旧值 → **永不退出**
- 加 volatile → 读强制从主存读 → 正常退出
- **方法引用**:`new Thread(vd::work, "worker")`
### 题目 2:计数器问题升级 — volatile 不保证原子性 vs synchronized ⭐⭐⭐⭐
**知识点**:count++ 读-改-写 3 步、volatile 不保证原子性、synchronized 保证原子性、线程数组 + join()
`volatile Integer count` + `synchronized increment()`,1000 线程并发:
- 只加 volatile:count **小于 1000**(读-改-写 3 步被打断,多个线程读旧值覆盖)
- 加 synchronized:count **必然是 1000**(同一时刻只有一个线程执行)
- 用 `for (Thread t : threads) t.join()` 等待所有线程结束再打印
### 题目 3:ReentrantLock 可重入锁 — 四种加锁用法计数器 ⭐⭐⭐
**知识点**:`Lock` 接口、`lock()` / `unlock()`、**unlock 必须放 finally**、公平锁/非公平锁、方法引用
四种加锁方法 + 10000 线程验证 count 正确:
```java
// ① 基本用法:lock + try + finally unlock(unlock 必须放 finally,否则死锁)
lock.lock();
try { count++; } finally { lock.unlock(); }
// ② tryLock():拿不到就算了,避免死锁
if (lock.tryLock()) { try { count++; return true; } finally { lock.unlock(); } }
return false;
// ③ tryLock(timeout):最多等 1 秒
if (lock.tryLock(1, TimeUnit.SECONDS)) { ... }
// ④ lockInterruptibly():等待锁中可被 interrupt() 打断,catch 后重设中断标志
lock.lockInterruptibly();
```
### 题目 4:线程池 — ThreadPoolExecutor 任务提交与执行流程 ⭐⭐⭐⭐
**知识点**:7 个参数、执行流程(核心线程 → 工作队列 → 非核心线程 → 拒绝策略)、拒绝策略、execute/shutdown
```java
ThreadPoolExecutor pool = new ThreadPoolExecutor(
2, // corePoolSize
4, // maximumPoolSize
60, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(2),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
```
提交 8 个耗时任务(sleep 2 秒),观察:**任务 1、2 → 核心线程;3、4 → 工作队列排队;5、6 → 队列满创建临时线程;7、8 → 线程满+队列满 → AbortPolicy 拒绝**。打印 `getActiveCount()` / `getQueue().size()`,最后 `pool.shutdown()`。
## ⭐ 重点编程题
### 题目 5:综合应用 — 用 Lock 锁改造卖票问题 ⭐⭐⭐⭐⭐
**知识点**:synchronized vs Lock 七维对比、Lock 解决数据竞争
把 homework0810 的卖票问题从 `synchronized(this)` 改造成 ReentrantLock:
```java
while (tickets > 0) {
lock.lock();
try { sell(); } finally { lock.unlock(); }
}
```
3 个窗口共用同一个 SellTicket 对象 + join() 等待,验证无相同票/负数票。
---
# 第 22 章 反射(08-12~08-13)
> **出处**:`课后作业/2026年8月12日-作业.md`、`课后作业/2026年8月13日-作业.md`、`课堂练习题/20260812-反射练习.md`、`课堂练习题/20260813-反射Field字段练习.md`
> **反射核心口诀**:
> - 获取 Class 对象三种方式:`类名.class`(编译期最安全)/ `对象.getClass()`(需实例)/ `Class.forName("全类名")`(最灵活、框架最常用)
> - **"含 Declared 的能拿私有"**:`getDeclaredXxx(s)` 本类全部含 private、不含父类;`getXxx(s)` 只拿 public 含父类继承
> - **暴力反射**:`setAccessible(true)` 临时取消访问权限检查
> - **invoke 四种调用规律**:实例方法传对象 / 静态方法传 null / void 返回 null / private 先 setAccessible(true)
## 🎯 核心编程题
### 题目 1:反射遍历 SysUser 四个构造方法创建对象 ⭐⭐⭐
**知识点**:`getConstructors()` / `getDeclaredConstructors()`、`getConstructor(参数类型...)` / `getDeclaredConstructor`、`newInstance()`、`setAccessible(true)`
SysUser 有 4 个构造(public 无参 / private 二参 / public 六参 / private 四参):
```java
// ① public 无参
clazz.getConstructor().newInstance();
// ② public 六参
clazz.getConstructor(String.class, String.class, String.class, String.class, String.class, String.class)
.newInstance(id, username, password, name, phone, email);
// ③ private 二参(必须暴力反射)
Constructor> c = clazz.getDeclaredConstructor(String.class, String.class);
c.setAccessible(true); // 放开私有访问权限
c.newInstance("admin", "admin888");
```
每个对象 `instanceof SysUser` 判断 + 打印 `toString()` 验证。
> 对比实验:注释 `setAccessible(true)` 抛 IllegalAccessException;用不带 Declared 的 `getConstructor` 拿 private 抛 NoSuchMethodException。
### 题目 2:反射给私有属性赋值 — Field 字段反射 + 暴力反射 ⭐⭐⭐⭐
**知识点**:`getDeclaredField("属性名")`、`setAccessible(true)`、`field.set(对象, 值)` / `field.get(对象)`
```java
Class> clazz = Class.forName("course.Student");
Object obj = clazz.getConstructor().newInstance(); // 反射创建对象
Field f = clazz.getDeclaredField("name");
f.setAccessible(true);
f.set(obj, "张三");
System.out.println(f.get(obj)); // 读取私有属性值
```
### 题目 3:通用工具 — 遍历打印任意类的所有字段 ⭐⭐⭐
**知识点**:`getDeclaredFields()`、`field.getModifiers()` + `Modifier.toString()`、`getType().getSimpleName()`、`getName()`
```java
public static void printFields(Class> clazz) {
for (Field field : clazz.getDeclaredFields()) {
String modifier = Modifier.toString(field.getModifiers());
String type = field.getType().getSimpleName();
String name = field.getName();
System.out.println(modifier + " " + type + " " + name);
}
}
printFields(Student.class);
printFields(String.class); // JDK 核心类也能反射
```
### 题目 4:暴力反射调用私有方法与静态方法 ⭐⭐⭐⭐
**知识点**:`getDeclaredMethod`、`setAccessible(true)`、`invoke(对象)` / `invoke(null)`、通用工具
封装不区分权限的通用工具 `invokeAnyMethod`:
```java
public static Object invokeAnyMethod(Object obj, String methodName, Object... args) throws Exception {
Class>[] paramTypes = new Class[args.length];
for (int i = 0; i < args.length; i++) paramTypes[i] = args[i].getClass();
Method m = obj.getClass().getDeclaredMethod(methodName, paramTypes);
m.setAccessible(true); // 暴力反射
return m.invoke(obj, args); // 实例方法传对象;静态方法 obj 传 null
}
// 调用 private 实例方法 read() → invoke(s)
// 调用 private static 方法 write() → invoke(null)
```
> **invoke 四种调用规律**:①实例方法传对象 ②静态方法传 null ③void 返回 null ④private 先 setAccessible(true)。静态方法不依赖对象,传什么都会被忽略。
### 题目 5:综合实战 — 模拟测试框架(JUnit 简化版)⭐⭐⭐⭐⭐
**知识点**:反射三件套(Constructor + Field + Method)、`getDeclaredMethods()` 扫描、`startsWith("test")` 过滤、**`InvocationTargetException` → `getCause()`**
给 Student 补充 3 个 private 测试方法(testAdd 正常 / testHello 正常 / testFail 故意抛异常),写迷你测试框架:
```java
Object obj = Student.class.getConstructor().newInstance(); // 反射创建被测对象
int pass = 0, fail = 0;
for (Method m : Student.class.getDeclaredMethods()) {
if (m.getName().startsWith("test")) { // 过滤测试方法
m.setAccessible(true);
try {
m.invoke(obj); // 暴力反射调用
System.out.println("测试通过:" + m.getName()); pass++;
} catch (InvocationTargetException e) {
System.out.println("测试失败:" + m.getName() + ",原因:" + e.getCause().getMessage()); fail++;
}
}
}
System.out.println("测试通过 " + pass + " 个,失败 " + fail + " 个");
```
> 方法内部抛异常 → invoke 抛 **InvocationTargetException**(包装一层),需 `getCause()` 取真实异常;这就是 JUnit 扫描 @Test 注解方法的底层原理。
## ⭐ 重点编程题
### 题目 6:反射读取/修改 public 字段 + 通用工具 ⭐⭐⭐
**知识点**:`getField("字段名")`、`field.get/set`、封装 `readField` / `setField`
用反射修改 public 字段 email/phone 后,**用普通访问 `s.email` 验证** —— 反射 set 与普通访问是同一份数据。
### 题目 7:通用工具 — 不区分权限字段读写 ⭐⭐⭐⭐
**知识点**:`getDeclaredField` + `setAccessible(true)` + `set/get`
```java
public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
Field f = obj.getClass().getDeclaredField(fieldName);
f.setAccessible(true);
f.set(obj, value);
}
public static Object getFieldValue(Object obj, String fieldName) throws Exception { ... f.get(obj) ... }
```
### 题目 8:综合实战 — 操作静态字段 + 模拟 ORM 映射 ⭐⭐⭐⭐⭐
**知识点**:静态字段反射操作(`get(null)` / `set(null, 值)`)、ORM 底层原理(Field.set 映射数据库行→Java 对象)
**① 静态字段**:`schoolField.get(null)` 读取、`schoolField.set(null, "哈尔滨佛学院")` 修改,`Student.school` 直接访问验证全类共享(静态成员属于类、不传对象)。
**② 模拟 ORM**:通用方法 `mapToObject(Map row, Class> clazz)` —— 反射创建空对象 + `getDeclaredFields()` 遍历 + 字段名匹配 row 的 key + `setAccessible(true)` + `field.set(obj, row.get(fieldName))`。换实体类不改代码(MyBatis 结果映射的底层)。
> 数据库字段 `user_name` vs Java 属性 `userName`(下划线转驼峰)就是 MyBatis `mapUnderscoreToCamelCase` 的底层逻辑。
### 题目 9:通用工具 — 遍历打印任意类的所有方法 ⭐⭐⭐
**知识点**:`getMethods()`(public 含父类继承)vs `getDeclaredMethods()`(本类全部含 private)、`getParameterTypes()` + Stream 映射
```java
public static void printMethods(Class> clazz, boolean declared) {
Method[] methods = declared ? clazz.getDeclaredMethods() : clazz.getMethods();
for (Method m : methods) {
List params = Arrays.stream(m.getParameterTypes())
.map(Class::getSimpleName).collect(Collectors.toList());
System.out.println(m.getName() + "(" + params + ") 返回值=" + m.getReturnType().getSimpleName());
}
}
```
> `getMethods()` 能看到 toString/hashCode 等 Object 继承方法;`getDeclaredMethods()` 能看到 private 的 read/write。
### 题目 10:反射调用实例方法 + 通用工具(无参/带参/重载)⭐⭐⭐⭐
**知识点**:`getMethod("方法名", 参数类型...)`、重载必须传参数类型、`invoke(对象, 参数...)`、void 返回 null
```java
// 封装通用工具:根据 args 动态计算参数类型数组
public static Object invokeMethod(Object obj, String methodName, Object... args) throws Exception {
Class>[] paramTypes = new Class[args.length];
for (int i = 0; i < args.length; i++) paramTypes[i] = args[i].getClass();
Method m = obj.getClass().getMethod(methodName, paramTypes); // 重载必须传参数类型
return m.invoke(obj, args);
}
// void 方法 invoke 返回 null;有返回值返回 Object 可强转
```
### 题目 11:配置驱动 + 反射 — 模拟框架底层(Spring IOC 简化版)⭐⭐⭐⭐⭐
**知识点**:`Properties` 加载配置文件、`Class.forName` 动态加载、反射 Constructor + Field + Method 全家桶、配置与代码分离
`student.properties` 配置类名/属性/方法名,代码只写"读配置 + 反射"通用逻辑:
```java
Properties props = new Properties();
props.load(ClassLoader.getSystemClassLoader().getResourceAsStream("student.properties"));
Class> clazz = Class.forName(props.getProperty("student.className")); // 动态加载类
Object obj = clazz.getConstructor().newInstance();
// 反射给属性赋值 + getMethod(配置的方法名).invoke(obj) 调用
```
> **换类不改代码** —— 把配置文件改成另一个类一行代码不改即可运行,这就是"配置驱动 + 反射解耦",也是 Spring IOC 创建 Bean 的过程。
---
## 📌 复习建议
1. **基础语法阶段(第 1~4 章)**:重点练习三大排序算法(冒泡/选择/插入)、方法 4 种声明方式、循环嵌套打印图形 —— 这些是笔试手写代码的高频题。
2. **面向对象阶段(第 5~10 章)**:封装+构造+继承+抽象类+接口+多态组合出题最多,重点做 **MyArray 可变数组**、**模板方法在线考试系统**、**智能家居控制系统**、**支付系统(匿名内部类)**。
3. **集合与函数式阶段(第 12~16 章)**:**期末大作业"学生信息管理系统"** 是 JavaSE 集大成者,务必完整实现;HashMap 底层原理、Comparable/Comparator 区别、Lambda 与匿名内部类区别是必答简答题。
4. **IO 与多线程阶段(第 17~21 章)**:文件复制器、成绩排序写回、三种多线程实现方式、synchronized/Lock 卖票问题、volatile 可见性 —— 每个知识点都有固定套路,建议按框架代码默写。
5. **反射阶段(第 22 章)**:把握"Declared + setAccessible(true)"核心套路,**模拟 JUnit 测试框架**是反射三件套的最佳综合练习。
---
> 本文档由课后作业与课堂练习题整理而成,题目详细要求、思考题与参考代码请回看对应日期原文。