跳到内容

元数据卡

  • 前置知识:第8章(上)继承、extends
  • 预计时间:15 分钟
  • 阅读模式:概念理解 + 动手
  • 完成标志:能用父类引用指向子类对象,理解动态绑定

你的进度

你学会了用 extends 把公共代码抽到父类 MessageSender 里,三个通信类不再写重复代码了。但现在村口需要一个新的东西:一个"调度中心"——它不管发消息的是马、鸽子还是喇叭,只要能 send() 就行。

先别用多态,看看老办法有多痛苦:

java
// 没有多态的情况——每多一种通信方式就要加一个新方法
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()


第一幕:多态——动态绑定

有继承之后,一切都变了:

java
// DispatchCenter.java — 利用多态
public class DispatchCenter {
    public void dispatch(MessageSender sender) { // 参数类型是父类
        sender.send(); // 实际调用子类的方法
    }
}

语言:Java 17+ 如何运行

java
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 一行不改。

这就是多态——"多种形态"。关键理解:

  1. 编译时看左边MessageSender h = new Horse(...)。编译器知道 hMessageSender 类型,所以只允许你调用 MessageSender 上定义的方法。
  2. 运行时看右边:当 h.send() 执行时,JVM 一看 h 实际指向 Horse 对象——它调的是 Horse.send(),不是 MessageSender.send()

这叫动态绑定。程序里不需要写 if (类型判断) { 转成某类再调用 }——编译器做的就是这个判断,只不过在运行时刻。


第二幕:instanceof——我得确认一下

你在调度中心里还要处理一些特殊情况。比如信鸽要加急收费,马要登记骑士姓名。但这些特殊操作只对某个子类有效:

java
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 类型——返回 truefalse。它回答:"这个对象的实际类型是 Horse 吗?"

Java 16 引入了更简洁的写法——模式匹配 instanceof

java
// Java 16+
if (sender instanceof Horse horse) { // 匹配成功,horse 自动就绪
    System.out.println("登记骑士: " + horse.getRiderName());
}

语言:Java 16+ 效果:等价于传统的 instanceof + 强制类型转换,但省去了一行变量声明,且变量作用域限定在 if 块内。


旅人笔记

多态 = 编译时看左边类型,运行时看右边对象。 父类引用可以指向子类对象。 instanceof 检查实际类型,向下转型后可调用子类特有方法。 新加子类无需改动调用方——这就是"可扩展"。

下一站预告

多态让你写出"只依赖抽象、不依赖具体"的代码。但有时候你需要让子类强制实现某个方法——下一站,@Override 和方法重写。

Built with VitePress | Software Systems Atlas