# 2026-07-23 JavaSE 课后作业 > **课程内容**:抽象类(abstract)、final 关键字、模板方法设计模式、代码块(局部/构造/静态)、接口(Interface)、接口 JDK8+ 新特性(默认方法/静态方法/私有方法) > > **涉及前序知识**:继承、构造方法、方法重写、多态、封装 > > **提交方式**:在 `提交\姓名\` 目录下创建对应的 Java 源文件 > > **截止时间**:下次上课前 --- ## 📌 本次作业重要说明 ### 命名要求 | 项目 | 要求 | |------|------| | **包名** | **必须按题目指定的包名创建**(全小写) | | **类名** | 自由命名,但需**见名知意**(如实体类用 `Printer`、`EmailNotifier` 等均可) | | **测试类** | 建议命名为 `TestXxx` 或 `XxxTest` | | **文件名** | 必须与类名一致 | ### 提交目录结构示例 ``` 提交\ └─ 张三\ ├─ p1_printer\ ← 第 1 题的包 │ ├─ Printer.java ← 抽象父类 │ ├─ Connectable.java ← 接口 │ ├─ LaserPrinter.java ← 子类(继承 + 实现) │ ├─ InkjetPrinter.java ← 子类(继承 + 实现) │ └─ TestPrinter.java ← 测试类 └─ p2_notification\ ← 第 2 题的包 ├─ Notifiable.java ← 接口(含默认方法) ├─ EmailNotifier.java ← 实现类 ├─ SMSNotifier.java ← 实现类 └─ TestNotification.java ← 测试类 ``` > ⚠ **注意**:包名必须严格按题目要求书写(全小写),目录结构必须与包结构一致。 --- ## 第 1 题:抽象类 + 接口——Printer 打印机体系 ⭐⭐ **包名**:`p1_printer` **知识点**:抽象类定义与使用、接口定义与实现、类同时继承抽象类并实现接口、方法重写、多态 ### 需求说明 某公司需要开发一个打印机管理系统。不同类型的打印机有 **共有的属性**(品牌、型号),也有 **共同的连接规范**(连接、打印、关闭)。请使用 **抽象类 + 接口** 来设计这个体系。 ### 类设计 #### Connectable 接口 - **抽象方法**:`void connect()` —— 连接设备 - **抽象方法**:`void print(String content)` —— 执行打印(参数为待打印内容) - **抽象方法**:`void close()` —— 关闭设备 #### Printer 抽象类 - **私有属性**:`brand`(品牌,String)、`model`(型号,String) - **有参构造方法**:`Printer(String brand, String model)` - **getter/setter** - **普通方法**:`showInfo()` —— 输出 `"打印机:xxx 品牌:xxx"`(xxx 为型号和品牌) - **抽象方法**:`void maintenance()` —— 维护保养(不同打印机保养方式不同) #### LaserPrinter 类(激光打印机) - **继承** `Printer` 抽象类,**实现** `Connectable` 接口 - **新增私有属性**:`tonerLevel`(碳粉余量,int,百分比 0~100) - **构造方法**:`LaserPrinter(String brand, String model, int tonerLevel)` - **实现** `connect()` —— 输出 `"激光打印机已连接"` - **实现** `print(String content)` —— 输出 `"激光打印机打印:xxx"`(xxx 为 content) - **实现** `close()` —— 输出 `"激光打印机已关闭"` - **重写** `maintenance()` —— 输出 `"激光打印机保养:检查碳粉,当前余量:xxx%"` #### InkjetPrinter 类(喷墨打印机) - **继承** `Printer` 抽象类,**实现** `Connectable` 接口 - **新增私有属性**:`inkLevel`(墨水余量,int,百分比 0~100) - **构造方法**:`InkjetPrinter(String brand, String model, int inkLevel)` - **实现** `connect()` —— 输出 `"喷墨打印机已连接"` - **实现** `print(String content)` —— 输出 `"喷墨打印机打印:xxx"` - **实现** `close()` —— 输出 `"喷墨打印机已关闭"` - **重写** `maintenance()` —— 输出 `"喷墨打印机保养:检查墨水,当前余量:xxx%"` ### 测试类要求 **`TestPrinter` 类**(置于 `p1_printer` 包下): 1. 创建 `LaserPrinter` 对象(品牌:"惠普",型号:"HP1010",碳粉余量:80) 2. 创建 `InkjetPrinter` 对象(品牌:"爱普生",型号:"L3153",墨水余量:60) 3. 调用每个对象的 `showInfo()` 方法 4. 调用每个对象的 `connect()` → `print("Hello World")` → `close()` 三步操作 5. 调用每个对象的 `maintenance()` 方法 ### 思考题(不需编码,口头回答) 1. 如果把 `Connectable` 改为抽象类,让 `LaserPrinter` 直接继承它,会出现什么问题?(提示:Java 的单继承限制) 2. `Printer` 中使用抽象方法 `maintenance()` 的好处是什么?能否用普通方法代替? 3. `showInfo()` 方法是在抽象类中定义的普通方法,它在测试时表现出了什么特性? ### 预期输出 ``` ========== 激光打印机 ========== 打印机:HP1010 品牌:惠普 激光打印机已连接 激光打印机打印:Hello World 激光打印机已关闭 激光打印机保养:检查碳粉,当前余量:80% ========== 喷墨打印机 ========== 打印机:L3153 品牌:爱普生 喷墨打印机已连接 喷墨打印机打印:Hello World 喷墨打印机已关闭 喷墨打印机保养:检查墨水,当前余量:60% ``` > 💡 **提示**: > - 子类构造方法中要调用 `super(brand, model)` 初始化父类属性 > - 实现接口时使用 `implements` 关键字,继承抽象类时使用 `extends` 关键字,两者用逗号分隔:`extends Printer implements Connectable` > - 抽象类 Printer 中的 `maintenance()` 和接口 Connectable 中的三个方法 **都需要重写** --- ## 第 2 题:接口 + JDK8 默认方法——Notification 通知体系 ⭐⭐⭐ **包名**:`p2_notification` **知识点**:接口定义、接口 JDK8 默认方法(default)、接口 JDK8 静态方法(static)、实现类重写抽象方法、通过接口名调用静态方法 ### 需求说明 某系统需要发送多种类型的通知(邮件、短信、微信)。每种通知的 **发送逻辑不同**,但 **发送前需要校验参数**、**发送后需要记录日志**,这部分是公共行为。请使用 **接口 + JDK8 默认方法** 来设计。 ### 接口设计 #### Notifiable 接口 **抽象方法**(实现类必须重写): - `void doSend(String recipient, String message)` —— 执行具体的发送逻辑 **默认方法**(JDK8,不强制重写,实现类可直接继承使用): - `default boolean validateParams(String recipient, String message)` —— 校验参数 - 如果 `recipient` 或 `message` 为 `null` 或空字符串,输出 `"参数校验失败:收件人或消息不能为空"`,返回 `false` - 否则输出 `"参数校验通过"`,返回 `true` - `default void log(String level, String msg)` —— 记录日志 - 输出 `"[等级] 消息:内容"`(例如:`"[INFO] 消息:邮件发送成功"`) - `default void send(String recipient, String message)` —— **模板方法**(`final` 不能用在接口方法中,所以此处用 default 模拟) - 步骤①:调用 `validateParams(recipient, message)` 校验参数,如果返回 `false` 则直接结束 - 步骤②:调用 `doSend(recipient, message)` 执行具体发送 - 步骤③:调用 `log("INFO", "发送成功")` 记录日志 - 步骤④:输出 `"--- 发送流程结束 ---"` **静态方法**(JDK8,通过 `接口名.方法名()` 调用): - `static void printNotificationType()` —— 输出 `"通知系统 v1.0——支持邮件/短信/微信通知"` ### 实现类要求 #### EmailNotifier 类(实现 Notifiable) - **实现** `doSend(String recipient, String message)` —— 输出 `"发送邮件给 xxx:内容 - yyy"`(xxx 为 recipient,yyy 为 message) - **可选重写** `log(String level, String msg)` —— 输出 `"[邮件][等级] 消息:内容"` #### SMSNotifier 类(实现 Notifiable) - **实现** `doSend(String recipient, String message)` —— 输出 `"发送短信给 xxx:内容 - yyy"` - 默认方法 `log()` 和 `validateParams()` **不重写**,直接继承接口的默认实现 ### 测试类要求 **`TestNotification` 类**(置于 `p2_notification` 包下): 1. 调用 `Notifiable.printNotificationType()` 输出系统信息(静态方法调用) 2. 创建 `EmailNotifier` 对象,分别测试: - 调用 `send("admin@example.com", "系统升级通知")` —— 正常发送 - 调用 `send("", "测试")` —— 参数为空,应校验失败 3. 创建 `SMSNotifier` 对象,测试: - 调用 `send("13800138000", "您的验证码是1234")` —— 正常发送 ### 思考题(不需编码,口头回答) 1. 接口中的 `send()` 方法为什么不能像模板方法模式一样用 `final` 修饰?如果想让子类不能修改发送流程,有什么替代方案? 2. `EmailNotifier` 重写了 `log()` 方法,而 `SMSNotifier` 没有重写。测试时两者的日志输出有什么不同?这体现了接口默认方法的什么特性? 3. 接口中的静态方法 `printNotificationType()` 能否通过实现类对象调用?为什么? ### 预期输出 ``` 通知系统 v1.0——支持邮件/短信/微信通知 ========== 邮件通知(正常) ========== 参数校验通过 发送邮件给 admin@example.com:内容 - 系统升级通知 [邮件][INFO] 消息:发送成功 --- 发送流程结束 --- ========== 邮件通知(参数为空) ========== 参数校验失败:收件人或消息不能为空 ========== 短信通知 ========== 参数校验通过 发送短信给 13800138000:内容 - 您的验证码是1234 [INFO] 消息:发送成功 --- 发送流程结束 --- ``` > 💡 **提示**: > - 接口中的方法默认是 `public`,实现类重写时也必须用 `public` > - 默认方法用 `default` 关键字修饰,可以有方法体 > - 静态方法用 `static` 修饰,必须通过 `接口名.静态方法名()` 调用 > - 默认方法和静态方法都是 JDK8 新增的特性 > - `String` 类型判断空或空字符串:`recipient == null || recipient.isEmpty()` --- ## 📋 题目总览 | 序号 | 包名 | 核心知识点 | 难度 | |------|------|-----------|------| | 第 1 题 | `p1_printer` | 抽象类定义与使用、接口定义与实现、类同时继承抽象类并实现接口、方法重写 | ⭐⭐ | | 第 2 题 | `p2_notification` | 接口定义、JDK8 默认方法(default)、JDK8 静态方法(static)、模拟模板方法、方法重写 vs 默认继承 | ⭐⭐⭐ |