Skip to content
第 18 / 250 章后端⏱ 10 分钟阅读

第 18 章:多态

学习目标

  • 理解多态的本质:动态绑定
  • 掌握向上转型和向下转型
  • 学会 instanceof 和模式匹配
  • 理解多态的应用场景

一、什么是多态?

多态 = 同一个方法调用,在不同对象上有不同行为。

java
Animal animal1 = new Dog();      // ① 父类引用指向子类对象
Animal animal2 = new Cat();

animal1.makeSound();    // 汪汪汪
animal2.makeSound();    // 喵喵喵

// 同一个调用 makeSound(),表现不同 → 多态

二、多态的三要素

  1. 继承:子类继承父类
  2. 重写:子类重写父类方法
  3. 父类引用指向子类对象:向上转型
java
class Animal {
    public void sound() {
        System.out.println("动物叫");
    }
}

class Dog extends Animal {
    @Override
    public void sound() {
        System.out.println("汪汪汪");
    }
}

// ✅ 多态:父类引用指向子类对象
Animal a = new Dog();
a.sound();   // 汪汪汪(运行时绑定到 Dog 的实现)

三、向上转型

向上转型 = 子类对象赋给父类引用(自动转换,安全)。

java
Dog dog = new Dog();
Animal animal = dog;        // ① 自动向上转型
// animal 实际上还是 Dog 对象,只是被当作 Animal 看

向上转型的限制

java
Animal animal = new Dog();
animal.sound();      // ✅ 父类有的方法可以调用
// animal.bark();   // ❌ 编译报错:父类没有 bark 方法

向上转型后只能调用父类声明的方法,不能调用子类特有方法。

四、向下转型

向下转型 = 父类引用转回子类引用(需要强制转换,可能失败)。

java
Animal animal = new Dog();

// 必须先判断类型
if (animal instanceof Dog) {       // ① instanceof 类型检查
    Dog dog = (Dog) animal;         // ② 强制向下转型
    dog.bark();                      // ③ 现在可以调用子类方法
}

ClassCastException

java
Animal animal = new Cat();
Dog dog = (Dog) animal;    // ❌ 运行时 ClassCastException

⚠️ 向下转型必须用 instanceof 检查,否则可能运行崩溃。

模式匹配(JDK 16+)

java
// 传统写法
if (animal instanceof Dog) {
    Dog dog = (Dog) animal;
    dog.bark();
}

// ✅ 模式匹配:自动绑定变量
if (animal instanceof Dog dog) {    // ① 自动转型
    dog.bark();                      // ② 直接用
}

五、动态绑定机制

多态的核心:方法调用在运行时才决定调用哪个版本。

java
class Animal {
    public void sound() { System.out.println("A"); }
}
class Dog extends Animal {
    @Override
    public void sound() { System.out.println("D"); }
}

Animal a = new Dog();
a.sound();    // 输出 D(运行时看实际类型)

编译看左边,运行看右边 —— 多态的铁律。

六、多态的实际应用

6.1 统一参数

java
public class AnimalService {
    public void printSound(Animal animal) {    // ① 接受所有 Animal 子类
        animal.sound();
    }
}

AnimalService service = new AnimalService();
service.printSound(new Dog());    // 汪汪汪
service.printSound(new Cat());    // 喵喵喵

6.2 集合多态

java
Animal[] animals = { new Dog(), new Cat(), new Bird() };
for (Animal a : animals) {
    a.sound();   // 各自调用自己的实现
}

6.3 模板方法模式

java
abstract class DataProcessor {
    public final void process() {              // ① 模板方法(固定流程)
        load();
        parse();                                // ② 钩子方法(子类实现)
        save();
    }

    protected abstract void load();
    protected abstract void parse();
    protected abstract void save();
}

class CsvProcessor extends DataProcessor {
    @Override protected void load() { /* 加载 CSV */ }
    @Override protected void parse() { /* 解析 CSV */ }
    @Override protected void save() { /* 保存 */ }
}

七、多态的局限

7.1 字段没有多态

java
class Parent {
    public int x = 1;
}
class Child extends Parent {
    public int x = 2;
}

Parent p = new Child();
System.out.println(p.x);   // 输出 1(字段不参与多态)
System.out.println(((Child) p).x);  // 输出 2

字段没有多态,方法才有

7.2 static 方法没有多态

java
class Parent {
    public static void hello() { System.out.println("P"); }
}
class Child extends Parent {
    public static void hello() { System.out.println("C"); }
}

Parent p = new Child();
p.hello();   // 输出 P(static 方法不参与多态)

7.3 private 方法不可重写

java
class Parent {
    private void hello() { System.out.println("P"); }
}
class Child extends Parent {
    public void hello() { System.out.println("C"); }  // 不是重写,是新方法
}

八、完整代码示例

java
/**
 * 多态综合示例
 *
 * 配套文档:第 18 章 多态
 */

// ============ 父类 ============
class Animal {
    protected String name;

    public Animal(String name) {
        this.name = name;
    }

    public void makeSound() {
        System.out.println(name + " 发出声音");
    }

    public void move() {
        System.out.println(name + " 在移动");
    }
}

// ============ 子类 ============
class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }

    @Override
    public void makeSound() {
        System.out.println(name + " 汪汪汪");
    }

    public void fetch() {
        System.out.println(name + " 在捡球");
    }
}

class Cat extends Animal {
    public Cat(String name) {
        super(name);
    }

    @Override
    public void makeSound() {
        System.out.println(name + " 喵喵喵");
    }

    public void climb() {
        System.out.println(name + " 在爬树");
    }
}

// ============ 测试 ============
public class PolymorphismDemo {
    public static void main(String[] args) {
        // ============ 1. 多态:父类引用指向子类对象 ============
        System.out.println("=== 多态演示 ===");
        Animal a1 = new Dog("旺财");
        Animal a2 = new Cat("小花");

        a1.makeSound();    // 旺财 汪汪汪
        a2.makeSound();    // 小花 喵喵喵

        // ============ 2. 向上转型的限制 ============
        System.out.println("\n=== 向上转型 ===");
        // a1.fetch();     // ❌ 编译报错:Animal 没有 fetch
        // a2.climb();     // ❌ 编译报错:Animal 没有 climb

        // ============ 3. 向下转型 ============
        System.out.println("\n=== 向下转型 ===");
        if (a1 instanceof Dog) {
            Dog dog = (Dog) a1;
            dog.fetch();   // 旺财 在捡球
        }

        // ============ 4. 模式匹配(JDK 16+)============
        if (a2 instanceof Cat cat) {
            cat.climb();    // 小花 在爬树
        }

        // ============ 5. 多态数组 ============
        System.out.println("\n=== 多态数组 ===");
        Animal[] animals = { new Dog("A"), new Cat("B"), new Dog("C") };
        for (Animal animal : animals) {
            animal.makeSound();   // 各自的行为
        }
    }
}

输出

=== 多态演示 ===
旺财 汪汪汪
小花 喵喵喵

=== 向下转型 ===
旺财 在捡球

=== 模式匹配 ===
小花 在爬树

=== 多态数组 ===
A 汪汪汪
B 喵喵喵
C 汪汪汪

九、本章小结

要点关键
多态本质同一个调用,不同对象有不同行为
三要素继承 + 重写 + 父类引用指向子类
向上转型子类 → 父类,自动安全
向下转型父类 → 子类,强制,可能 ClassCastException
编译看左编译时看引用类型
运行看右运行时看实际类型
字段没多态字段不参与多态
static 没多态static 方法不参与多态

动手练习

练习 1:基础题

定义一个 Shape 抽象类(有 area() 方法),创建 CircleRectangle 子类,演示多态。

练习 2:进阶题

实现一个 Employee 类和 Manager 子类,Manager 重写 work() 方法。写一个 Company 类用多态统一管理员工。


下一章第 19 章:static 与 final 关键字

本站基于 VitePress 构建 · 由 Codebook 团队维护