课程内容:抽象类(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 ← 测试类
⚠ 注意:包名必须严格按题目要求书写(全小写),目录结构必须与包结构一致。
包名:p1_printer
知识点:抽象类定义与使用、接口定义与实现、类同时继承抽象类并实现接口、方法重写、多态
某公司需要开发一个打印机管理系统。不同类型的打印机有 共有的属性(品牌、型号),也有 共同的连接规范(连接、打印、关闭)。请使用 抽象类 + 接口 来设计这个体系。
void connect() —— 连接设备void print(String content) —— 执行打印(参数为待打印内容)void close() —— 关闭设备brand(品牌,String)、model(型号,String)Printer(String brand, String model)showInfo() —— 输出 "打印机:xxx 品牌:xxx"(xxx 为型号和品牌)void maintenance() —— 维护保养(不同打印机保养方式不同)Printer 抽象类,实现 Connectable 接口tonerLevel(碳粉余量,int,百分比 0~100)LaserPrinter(String brand, String model, int tonerLevel)connect() —— 输出 "激光打印机已连接"print(String content) —— 输出 "激光打印机打印:xxx"(xxx 为 content)close() —— 输出 "激光打印机已关闭"maintenance() —— 输出 "激光打印机保养:检查碳粉,当前余量:xxx%"Printer 抽象类,实现 Connectable 接口inkLevel(墨水余量,int,百分比 0~100)InkjetPrinter(String brand, String model, int inkLevel)connect() —— 输出 "喷墨打印机已连接"print(String content) —— 输出 "喷墨打印机打印:xxx"close() —— 输出 "喷墨打印机已关闭"maintenance() —— 输出 "喷墨打印机保养:检查墨水,当前余量:xxx%"TestPrinter 类(置于 p1_printer 包下):
LaserPrinter 对象(品牌:"惠普",型号:"HP1010",碳粉余量:80)InkjetPrinter 对象(品牌:"爱普生",型号:"L3153",墨水余量:60)showInfo() 方法connect() → print("Hello World") → close() 三步操作maintenance() 方法Connectable 改为抽象类,让 LaserPrinter 直接继承它,会出现什么问题?(提示:Java 的单继承限制)Printer 中使用抽象方法 maintenance() 的好处是什么?能否用普通方法代替?showInfo() 方法是在抽象类中定义的普通方法,它在测试时表现出了什么特性?========== 激光打印机 ==========
打印机:HP1010 品牌:惠普
激光打印机已连接
激光打印机打印:Hello World
激光打印机已关闭
激光打印机保养:检查碳粉,当前余量:80%
========== 喷墨打印机 ==========
打印机:L3153 品牌:爱普生
喷墨打印机已连接
喷墨打印机打印:Hello World
喷墨打印机已关闭
喷墨打印机保养:检查墨水,当前余量:60%
💡 提示:
- 子类构造方法中要调用
super(brand, model)初始化父类属性- 实现接口时使用
implements关键字,继承抽象类时使用extends关键字,两者用逗号分隔:extends Printer implements Connectable- 抽象类 Printer 中的
maintenance()和接口 Connectable 中的三个方法 都需要重写
包名:p2_notification
知识点:接口定义、接口 JDK8 默认方法(default)、接口 JDK8 静态方法(static)、实现类重写抽象方法、通过接口名调用静态方法
某系统需要发送多种类型的通知(邮件、短信、微信)。每种通知的 发送逻辑不同,但 发送前需要校验参数、发送后需要记录日志,这部分是公共行为。请使用 接口 + JDK8 默认方法 来设计。
抽象方法(实现类必须重写):
void doSend(String recipient, String message) —— 执行具体的发送逻辑默认方法(JDK8,不强制重写,实现类可直接继承使用):
default boolean validateParams(String recipient, String message) —— 校验参数
recipient 或 message 为 null 或空字符串,输出 "参数校验失败:收件人或消息不能为空",返回 false"参数校验通过",返回 truedefault 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——支持邮件/短信/微信通知"doSend(String recipient, String message) —— 输出 "发送邮件给 xxx:内容 - yyy"(xxx 为 recipient,yyy 为 message)log(String level, String msg) —— 输出 "[邮件][等级] 消息:内容"doSend(String recipient, String message) —— 输出 "发送短信给 xxx:内容 - yyy"log() 和 validateParams() 不重写,直接继承接口的默认实现TestNotification 类(置于 p2_notification 包下):
Notifiable.printNotificationType() 输出系统信息(静态方法调用)EmailNotifier 对象,分别测试:
send("admin@example.com", "系统升级通知") —— 正常发送send("", "测试") —— 参数为空,应校验失败SMSNotifier 对象,测试:
send("13800138000", "您的验证码是1234") —— 正常发送send() 方法为什么不能像模板方法模式一样用 final 修饰?如果想让子类不能修改发送流程,有什么替代方案?EmailNotifier 重写了 log() 方法,而 SMSNotifier 没有重写。测试时两者的日志输出有什么不同?这体现了接口默认方法的什么特性?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 默认继承 | ⭐⭐⭐ |