元数据卡
- 前置知识:第8章(上)继承、extends
- 预计时间:15 分钟
- 阅读模式:概念理解 + 动手
- 完成标志:能用父类引用指向子类对象,理解动态绑定
你的进度
你学会了用 extends 把公共代码抽到父类 MessageSender 里,三个通信类不再写重复代码了。但现在村口需要一个新的东西:一个"调度中心"——它不管发消息的是马、鸽子还是喇叭,只要能 send() 就行。
先别用多态,看看老办法有多痛苦:
// 没有多态的情况——每多一种通信方式就要加一个新方法
public class DispatchCenter {
public void sendByHorse(Horse h) { h.send(); }
public void sendByPigeon(Pigeon p) { p.send(); }
public void sendByLoudspeaker(Loudspeaker l) { l.send(); }
// 每多一种通信方式,就要加一个新方法……
}太傻了。要加烽火台?又写一个 sendByBeacon()。
你的任务:能不能只写一个 dispatch() 方法,不管传入什么类型,它都能正确调用对应的 send()?
第一幕:多态——动态绑定
有继承之后,一切都变了:
// DispatchCenter.java — 利用多态
public class DispatchCenter {
public void dispatch(MessageSender sender) { // 参数类型是父类
sender.send(); // 实际调用子类的方法
}
}语言:Java 17+ 如何运行:
public class Main {
public static void main(String[] args) {
DispatchCenter center = new DispatchCenter();
MessageSender h = new Horse("敌军来袭", "张三");
MessageSender p = new Pigeon("天气转晴", 2);
MessageSender l = new Loudspeaker("今晚开村民大会");
center.dispatch(h); // 调用 Horse 的 send()
center.dispatch(p); // 调用 Pigeon 的 send()
center.dispatch(l); // 调用 Loudspeaker 的 send()
}
}语言:Java 17+ 预期输出(略去时间戳):
消息: 敌军来袭
骑士 张三 策马奔腾!
消息: 天气转晴
加急!信鸽起飞!
消息: 今晚开村民大会
大喇叭响起!你试试:加一个 Beacon 类继承 MessageSender——只需要写新类,DispatchCenter 一行不改。
这就是多态——"多种形态"。关键理解:
- 编译时看左边:
MessageSender h = new Horse(...)。编译器知道h是MessageSender类型,所以只允许你调用MessageSender上定义的方法。 - 运行时看右边:当
h.send()执行时,JVM 一看h实际指向Horse对象——它调的是Horse.send(),不是MessageSender.send()。
这叫动态绑定。程序里不需要写 if (类型判断) { 转成某类再调用 }——编译器做的就是这个判断,只不过在运行时刻。
第二幕:instanceof——我得确认一下
你在调度中心里还要处理一些特殊情况。比如信鸽要加急收费,马要登记骑士姓名。但这些特殊操作只对某个子类有效:
public class DispatchCenter {
public void dispatch(MessageSender sender) {
sender.send(); // 公共逻辑
// 如果 sender 是 Horse,需要登记骑士
if (sender instanceof Horse) {
Horse horse = (Horse) sender; // 强制向下转型
System.out.println("登记骑士: " + horse.getRiderName());
}
}
}语言:Java 17+ 预期输出:只有传入 Horse 对象时,才会打印"登记骑士:……"
instanceof 是一个二元操作符——对象 instanceof 类型——返回 true 或 false。它回答:"这个对象的实际类型是 Horse 吗?"
Java 16 引入了更简洁的写法——模式匹配 instanceof:
// Java 16+
if (sender instanceof Horse horse) { // 匹配成功,horse 自动就绪
System.out.println("登记骑士: " + horse.getRiderName());
}语言:Java 16+ 效果:等价于传统的 instanceof + 强制类型转换,但省去了一行变量声明,且变量作用域限定在 if 块内。
旅人笔记
多态 = 编译时看左边类型,运行时看右边对象。 父类引用可以指向子类对象。
instanceof检查实际类型,向下转型后可调用子类特有方法。 新加子类无需改动调用方——这就是"可扩展"。
→ 下一站预告
多态让你写出"只依赖抽象、不依赖具体"的代码。但有时候你需要让子类强制实现某个方法——下一站,@Override 和方法重写。