# 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 测试框架**是反射三件套的最佳综合练习。 --- > 本文档由课后作业与课堂练习题整理而成,题目详细要求、思考题与参考代码请回看对应日期原文。