JavaSE重点核心编程题.md 72 KB

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 年不是闰年

// 核心判断:能被4整除但不能被100整除,或能被400整除
boolean isLeap = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);

题目 2:三个数比大小 ⭐

知识点:三目运算符、if-else

定义三个整数变量 abc,找出其中的最大值并输出。

  • 方法一:使用三目运算符嵌套实现
  • 方法二:使用 if-else 实现(两种方法都写在同一个文件中)

    int max = (a > b ? a : b) > c ? (a > b ? a : b) : c;
    

题目 3:水仙花数判定 ⭐⭐

知识点:算术运算符(/%)、if-else

"水仙花数"指一个三位数,其各位数字的立方和等于该数本身。例如:153 = 1³ + 5³ + 3³

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(选做)

定义两个整数 ab 和字符变量 operator(取值为 '+'/'-'/'*'/'/'/'%'),用 if-else if-else 多分支判断输出运算结果。除号为 /、取模为 % 时需判断除数是否为 0,输出"除数不能为 0"。

⭐ 重点编程题

题目 6:数字加密系统 ⭐⭐⭐

知识点:算术运算符、位运算符、三目运算符、综合运用

设计一个 4 位数字加密系统:

  1. 输入一个 4 位整数(如 1234
  2. 对每一位数字加 5 → 对 10 取余 → 第 1 位与第 4 位交换、第 2 位与第 3 位交换
  3. 输出加密后的数字(可选:加密结果 ^ 0xAA 再异或)

题目 7:位运算权限系统 ⭐⭐⭐

知识点:位运算符(&|~<<)、综合运用

用位运算实现权限控制:

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:程序员智商测试 ⭐⭐⭐

知识点:运算符优先级、自增/自减、短路特性

先手算再运行验证:

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 个

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 标记本轮是否有交换,无交换提前结束

    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:方法中调用方法 — 温度转换 ⭐⭐

知识点:方法中调用另一个方法

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)。

Random ran = new Random();
String password = "";
// 循环8次:ran.nextInt(2) 决定当前位是字母还是数字
// 字母:(char)(ran.nextInt(26) + 65);数字:(char)(ran.nextInt(10) + 48)

题目 5:数组随机打乱(Fisher-Yates 洗牌算法)⭐⭐⭐⭐

知识点:数组作为方法参数、Random、数组交换

// 从最后一个元素往前遍历(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 电器体系 ⭐

知识点:继承的格式、子类调用父类方法

父类 AppliancepowerOn()/powerOff()),子类 TVchangeChannel())、WashingMachinestartWash())。观察子类直接使用父类方法,不需重复定义。

题目 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),重写全部抽象方法

    // 类同时继承抽象类并实现接口: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())。

// 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 <ul><li>...</li></ul> 列表
  5. String.joinString.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 接口、冒泡排序

StudentManagersortStudents(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 否则抛 IllegalArgumentExceptionwithdraw() 金额≤0 或超余额抛异常;parseInt() 空串/非数字字符手动抛 NumberFormatException;验证 throw 后代码不执行(不可达语句)。

⭐ 重点编程题

题目 3:用户注册验证系统(自定义异常 + 多 catch)⭐⭐⭐⭐

知识点:自定义异常(继承 Exception)、throws 声明、多 catch、finally 操作日志

定义 UsernameEmptyException / UsernameLengthException / PasswordEmptyException / PasswordWeakException / AgeInvalidExceptionRegisterService.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<Student> 存储 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<E>(无参默认容量 10、自动扩容、CRUD、toString)

题目 5:进阶综合 — 教室座位管理系统 ⭐⭐⭐⭐

知识点ArrayList<ArrayList<Student>> 嵌套模拟二维结构

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<String> queue = new LinkedList<>() 模拟叫号:客户 A/B/C 依次 offer 入队 → peek 看队首 → poll 叫号出队 → 新客户 D 入队 → 再次 poll → 输出剩余。空队列 poll()/peek() 返回 null 不抛异常

Queue<String> 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<String> 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<N>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<String, Integer>(学号→成绩),测试 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

Map<String, Integer> 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<Student>按成绩降序,成绩相同再按姓名

@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、可变参数本质即数组、可变参数置末

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 标准格式、三条省略规则

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<Student, String>,按 compareTo 规则自动排序。


第 16 章 Stream 流与函数式编程(08-04)

出处课堂练习题/20260804-Stream流练习.md课后作业/2026年8月4日-作业.md(期末综合大作业)

🎯 核心编程题

题目 1:生成 Stream 流的四种方式 ⭐

知识点Collection.stream() / Map 转 Set / Arrays.stream() / Stream.of()

List<String> list = ...;  list.stream();
map.keySet().stream();   map.values().stream();
Arrays.stream(array);
Stream.of("长贵", "赵四", "刘能");

题目 2:filter 过滤 + forEach 遍历 ⭐⭐

知识点:filter(Predicate)、forEach(Consumer)、方法引用

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、分页思想

// 分页通用公式: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

list.stream().forEach(System.out::println).count();   // 编译报错!终结方法后流已结束

题目 6:collect 收集操作 ⭐⭐⭐

知识点Collectors.toList() / toSet()

List<String> l = list.stream().distinct().collect(Collectors.toList());
Set<String> s = list.stream().filter(x -> x.contains("伊")).collect(Collectors.toSet());
// toList() 返回不可变集合,add 抛 UnsupportedOperationException

⭐ 重点编程题

题目 7:Collectors.toMap 收集成 Map ⭐⭐⭐⭐

知识点toMap(keyMapper, valueMapper)、Function 函数式接口、Lambda vs 匿名内部类

Map<Integer, Student> map = list.stream()
    .collect(Collectors.toMap(student -> student.getId(), student -> student));
// 匿名内部类等价写法:new Function<Student, Integer>() { apply(...) }
// 键重复默认抛 IllegalStateException

题目 8:综合实战 — 员工信息流式处理 ⭐⭐⭐⭐

知识点:filter / distinct / count / collect / toMap 综合、方法引用

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<String, String> 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<Student>, Studyable(学号 id/班级/成绩列表,compareTo 按平均分降序二次比较学号,equals/hashCode 以学号判定)、TeacherCourseScore
  • 模块二(exception 包):4 个自定义异常(继承 Exception):ScoreOutOfBoundsException / StudentNotFoundException / CourseNotFoundException / DuplicateStudentException
  • 模块三(manager 包 + main):StudentManager(增删改查,重复学号抛异常,findById 用迭代器)、CourseManagerScoreManagerHashMap<String, List<Score>> 按学号分组)、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 / FileOutputStreamread(byte[]) / write(byte[], 0, len)、缓冲区 byte[4096]-1 判断、close、耗时统计

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 / mkdirscreateNewFiledeleteisFile / isDirectory / existsgetName / 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)

// 写: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 / BufferedWriterreadLine() 逐行读取、newLine() 换行、split("-")Integer.parseInt()、ArrayList + Collections.sort

D:/scores.txt("姓名-成绩"顺序乱)→ 五步闭环:读取 → 处理(split+parseInt)→ 集合(封装 Student)→ 排序(按成绩降序)→ 写回(带名次)。

BufferedReader br = new BufferedReader(new FileReader("D:/scores.txt"));
ArrayList<Student> 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 IOExceptionCopy01(普通字节流 + byte[8192] + try-catch-finally)、BufferedCopyBufferedOutputStream 包装底层流)。复制同一大文件对比耗时,验证"缓冲流更快"。

关闭顺序:Copy01 先关 fos 再关 fis;BufferedCopy 先关缓冲流再关底层流。

题目 4:字符集(Charset)与乱码实验 ⭐⭐⭐⭐

知识点Charset.forName("GBK")FileWriter(String, Charset) / FileReader(String, Charset)、编码/解码、乱码原理

用 GBK 写入中文 → 默认字符集(UTF-8)读 → 乱码;改用 GBK 读 → 正常。一个汉字 GBK 占 2 字节、UTF-8 占 3 字节。

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整个集合一次性序列化,再一次性反序列化读回强转遍历。

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<Student> readList = (ArrayList<Student>) 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 Threadsuper(name) 传线程名,run() 中 1~100 边加边打印 this.getName() + "--->" + i,结束打印求和结果(5050)。main 中创建两个线程 start() 观察输出交错。

直接调 run() 不创建新线程,只是普通方法调用 —— 验证 run 与 start 的区别。

题目 4:多线程实现方式二 — 实现 Runnable 三种方式 ⭐⭐⭐

知识点implements RunnableThread.currentThread().getName()Thread(Runnable, name)、实现类对象/匿名内部类/Lambda

// 三种提供任务方式:
new Thread(new CountTask(), "任务线程");                  // ① 实现类对象
new Thread(new Runnable(){ public void run(){...} }, "匿名线程");  // ② 匿名内部类
new Thread(() -> { ... }, "Lambda线程");                 // ③ Lambda(Runnable 是函数式接口)
// main 主线程也循环打印,观察 4 种线程名交错(主线程与子线程并发,start() 不阻塞)

⭐ 重点编程题

题目 5:多线程实现方式三 — Callable + FutureTask 带返回值 ⭐⭐⭐⭐

知识点Callable<V>(call() 带返回值)、FutureTask<V> 包装、get() 阻塞获取

SumCallable implements Callable<Integer> 求 1~n 的和并 return sum;用 FutureTask<Integer> 包装后 new Thread(futureTask, "线程名").start()ft.get() 阻塞等待取回每个线程结果,main 中汇总。

三种方式对比:run() 无返回值 vs call() 有返回值;实现接口 vs 继承类。

题目 6:转换流字符集转码(UTF-8 → GBK)⭐⭐⭐

知识点InputStreamReader / OutputStreamWriter 转码、编码/解码

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_PRIORITYThread.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 正确:

// ① 基本用法: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

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:

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(参数类型...) / getDeclaredConstructornewInstance()setAccessible(true)

SysUser 有 4 个构造(public 无参 / private 二参 / public 六参 / private 四参):

// ① 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(对象)

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()

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:暴力反射调用私有方法与静态方法 ⭐⭐⭐⭐

知识点getDeclaredMethodsetAccessible(true)invoke(对象) / invoke(null)、通用工具

封装不区分权限的通用工具 invokeAnyMethod

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") 过滤、InvocationTargetExceptiongetCause()

给 Student 补充 3 个 private 测试方法(testAdd 正常 / testHello 正常 / testFail 故意抛异常),写迷你测试框架:

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

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<String, Object> 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 映射

public static void printMethods(Class<?> clazz, boolean declared) {
    Method[] methods = declared ? clazz.getDeclaredMethods() : clazz.getMethods();
    for (Method m : methods) {
        List<String> 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

// 封装通用工具:根据 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 配置类名/属性/方法名,代码只写"读配置 + 反射"通用逻辑:

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 测试框架是反射三件套的最佳综合练习。

本文档由课后作业与课堂练习题整理而成,题目详细要求、思考题与参考代码请回看对应日期原文。