正在加载...

Java 中的多态

把不同对象放进父类型变量,让同一个调用名能运行不同方法体。在 Machine 上保留打印 tone 的 horn。在 Truck 上重写 horn 以打印 honk。在 Car 上重写 horn 以打印 beep。在 Yard.java 中写出 Machine m = new Machine();、Machine t = new Truck(); 与 Machine c = new Car();,然后对每个调用 horn。用 javac Yard.java 编译,再运行 java Yard。屏幕应先显示 tone,再 honk,再 beep。第二个演示只把两个子类保存为 Machine 引用。把 equals 留给下一页——本课是一个父类型容纳多种形态。

一个父类型,三个 horn 方法体

abstract 页留下未完成的方法给子类填满。本页聚焦通过父类型变量发起调用。打开 Yard.java。保持公共类名为 Yard。若残留的仅 abstract 演示会淹没父类型主线,请删除它们,以及残留的 enum Level 文件、路径演示和任何键盘 Scanner。程序不得等待输入。不需要 import 行。
声明带有 horn 方法体的普通父类:
class Machine {
void horn() {
System.out.println("tone");
}
}
用 extends Machine 声明子类,并给出各自打印 honk 与 beep 的 horn 方法体。名称相同且参数列表为空,表示每个子类都 override 了父类方法。
在 Yard.main 内创建三个声明类型为 Machine 的变量:
Machine m = new Machine();
Machine t = new Truck();
Machine c = new Car();
然后调用:
m.horn();
t.horn();
c.horn();
三者的声明类型都是 Machine。真正的对象决定运行哪个 horn 方法体。

Yard Machine Truck Car horn polymorphism

java
class Machine {
    void horn() {
        System.out.println("tone");
    }
}

class Truck extends Machine {
    void horn() {
        System.out.println("honk");
    }
}

class Car extends Machine {
    void horn() {
        System.out.println("beep");
    }
}

public class Yard {
    public static void main(String[] args) {
        Machine m = new Machine();
        Machine t = new Truck();
        Machine c = new Car();
        m.horn();
        t.horn();
        c.horn();
    }
}

在保存 Yard.java 的文件夹中运行 javac Yard.java。当圆括号、花括号与分号都匹配时,javac 不会写出自己的行。然后运行 java Yard——不要写成 java Yard.java。运行命令去掉 .java 结尾。文件中只保留一个公共类,使名称匹配 Yard。辅助类型在本入门形状中不加 public。
屏幕先显示 tone,再 honk,再 beep。把这次运行走一遍。Java 从 Yard.main 开始。m 保存普通 Machine,所以 m.horn() 打印 tone。t 保存的是 Truck,尽管变量类型写着 Machine,所以 t.horn() 打印 honk。c 保存 Car,所以 c.horn() 打印 beep。调用写法相同。三个方法体。
读屏幕时指向每一处赋值,并对上对应的那一行。第一行属于普通机器。第二行属于藏在机器类型名字后面的 truck 对象。第三行属于藏在机器类型名字后面的 car 对象。这种配对游戏就是整课一次过完。
若你仍只看到 abstract 演示留下的 honk 再 park,请切到 polymorphism 教学文件并再次运行 java Yard。若每个变量都只写成 Truck 或 Car 类型,你还没展示本页要教的父类型形式——演示里请把赋值左侧保持为 Machine 类型。
看着屏幕把规则说出来:变量类型可以是父类,对象可以是子类;当子类 override 了方法时,调用运行子类的方法体。本页不要发明 equals 的 override。那个主题留给下一课。

通过 Machine 引用保存两个子类

第二个程序保留这些 override。main 只创建 Truck 与 Car,仍保存为 Machine,并对各自调用 horn。

Yard Truck and Car as Machine refs

java
class Machine {
    void horn() {
        System.out.println("tone");
    }
}

class Truck extends Machine {
    void horn() {
        System.out.println("honk");
    }
}

class Car extends Machine {
    void horn() {
        System.out.println("beep");
    }
}

public class Yard {
    public static void main(String[] args) {
        Machine t = new Truck();
        Machine c = new Car();
        t.horn();
        c.horn();
    }
}

用 javac Yard.java 编译,再运行 java Yard。屏幕先显示 honk,再 beep。第二个演示里没有普通 Machine 对象,但两个变量仍是 Machine 类型。子类对象提供方法体。这是同一套 polymorphism 思路,只是屏幕更短。
再读一遍赋值行:左边是 Machine,右边是 new Truck() 或 new Car()。左边点名你将通过其调用的父类型。右边点名真正的对象。两个子类都保留 extends Machine,这些赋值才合法。
若附近仍有残留 abstract 演示,可当作历史保留。本课请运行 polymorphism 教学文件,使屏幕主线是 tone / honk / beep 或 honk / beep,而不是 park。若 javac 抱怨重复的公共类,只让 Yard 保持 public。

哪个 horn 方法体在运行

📊 Who runs for each Machine variable

Variable Real object horn prints
m Machine tone
t Truck honk
c Car beep

与 abstract 填满对照

在 abstract 页,Machine 留下未完成的 horn,子类填满它,常常还带共享的 park。本页里 Machine 已有 tone 方法体,子类 override 它,父类型变量保存这些对象。你仍编译 Yard.java 并运行 java Yard。新记号是像 Machine t = new Truck(); 这样的父类型赋值,以及同一调用名下的三种不同打印。
若残留的 abstract 文件仍打开,你可能看到 abstract void horn(); 与 park。切到 polymorphism 文件,让 Machine 拥有普通 horn 方法体,并让 main 把 Machine 变量赋给不同对象。本页不要放 equals 演示。本页不要放键盘输入。

进入 equals 之前

你可以把 Machine 变量赋给 Machine、Truck 与 Car 对象,并看到 tone,再 honk,再 beep。你也可以只把两个子类保存为 Machine 引用,并看到 honk 再 beep。对每个保留的演示依次编译 Yard.java 并运行 java Yard。调用使用了方法体的拥有者。下一页是 equals,在那里用教学安全的方式比较两个对象是否相同。
保留三对象演示,以便清楚看到父类加子类。保留双子类演示,以便清楚看到父类型成对。本页不要放 equals 文件。这三条习惯是继续前进前的检查点。当 Machine 类型的 truck 变量打出 honk 时,polymorphism 完成本课任务,你已准备好进入下一题 equals。
最后再扫一遍文件夹:一个公共 Yard,父类与子类的 horn 方法体,main 中的父类型变量,无键盘等待,无强行 equals。对你打开的演示再跑一次 javac Yard.java 与 java Yard。若屏幕仍与表格一致,多种形态的调用就站稳了,课程可以在下一页进入 equals。

🧠 测试您的知识

准备开始

测试您的知识

通过这个互动测验挑战自己,看看你对这个主题的理解程度如何

❓
5
问题
🎯
70%
及格要求
♾️
∞
时间
🔄
∞
尝试次数

📝 说明

  • 仔细阅读每个问题
  • 为每个问题选择最佳答案
  • 您可以随时重新参加测验
  • 您的进度将显示在顶部