编译时多态和运行时多态

编译时多态和运行时多态

编译时多态(静态多态)和运行时多态(动态多态)是面向对象编程(OOP)中多态性实现的两种不同方式,分别在编译时和运行时决定方法的绑定。两者的实现方式、适用场景和特点有所不同。

1. 编译时多态(Compile-time Polymorphism)

编译时多态,也叫静态多态,是在编译阶段决定方法的调用。编译时多态主要通过**方法重载(Method Overloading)**来实现。

方法重载(Method Overloading)

方法重载是指在同一个类中定义多个方法,这些方法具有相同的方法名,但参数列表不同(参数的类型或数量不同)。Java 编译器根据方法调用时传入的参数类型和数量,在编译阶段决定调用哪个重载方法。

  • 特点
    • 方法名相同,但参数不同(可以是数量、类型或顺序的变化)。
    • 编译时根据传入参数类型选择匹配的方法。
    • 重载方法的返回类型不影响重载的决策。

示例代码:

class Example {
    void display(int a) {
        System.out.println("Integer: " + a);
    }

    void display(double a) {
        System.out.println("Double: " + a);
    }

    void display(String a) {
        System.out.println("String: " + a);
    }
}

public class Main {
    public static void main(String[] args) {
        Example obj = new Example();
        obj.display(5);         // 调用 display(int a)
        obj.display(3.14);      // 调用 display(double a)
        obj.display("Hello");   // 调用 display(String a)
    }
}
  • 解释:在上面的代码中,display() 方法被重载了三次,分别处理不同类型的参数(intdoubleString)。编译器会在编译时根据参数的类型来决定调用哪个版本的 display() 方法。

编译时多态的优势

  • 高效:编译器能够在编译阶段确定调用的方法,因此在运行时没有额外的开销。
  • 类型安全:由于编译时就确定了方法的调用,避免了运行时类型错误。

2. 运行时多态(Runtime Polymorphism)

运行时多态,也叫动态多态,是在程序运行时决定方法的调用。运行时多态通常是通过**方法重写(Method Overriding)**来实现。

方法重写(Method Overriding)

方法重写是子类重新定义父类中已有的方法,并提供不同的实现。当通过父类引用调用方法时,实际执行的是子类重写后的方法。此时方法的绑定是根据对象的实际类型,而不是引用类型来决定的。方法重写是实现运行时多态的关键。

  • 特点
    • 子类重写父类的方法,方法名和参数列表必须相同。
    • 运行时根据对象的实际类型来决定调用哪个方法。
    • 可以通过父类引用指向子类对象,表现出不同的行为。

示例代码:

class Animal {
    void sound() {
        System.out.println("Animal makes a sound");
    }
}

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

class Cat extends Animal {
    @Override
    void sound() {
        System.out.println("Cat meows");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal myDog = new Dog(); // Animal reference but Dog object
        Animal myCat = new Cat(); // Animal reference but Cat object

        myDog.sound(); // 输出: Dog barks
        myCat.sound(); // 输出: Cat meows
    }
}
  • 解释:在这个例子中,Animal 是父类,DogCat 是子类。尽管 myDogmyCat 都是 Animal 类型的引用,但它们分别指向 DogCat 对象。在调用 sound() 方法时,实际执行的是子类重写后的方法。

运行时多态的优势

  • 灵活性和可扩展性:通过父类类型的引用可以调用不同子类的实现,使得代码具有更高的灵活性和可扩展性。
  • 实现多态性:运行时多态允许在程序运行时决定对象的行为,这使得程序能够根据不同的对象表现出不同的行为。

总结:编译时多态与运行时多态的区别

特点 编译时多态(静态多态) 运行时多态(动态多态)
实现方式 方法重载(Method Overloading) 方法重写(Method Overriding)
方法绑定时机 编译时 运行时
决策依据 方法名相同,参数列表不同 方法名和参数列表相同,依据对象的实际类型
多态类型 静态多态,方法的调用在编译时就确定 动态多态,方法的调用在运行时决定
类型 方法签名不同(参数不同) 子类重写父类方法
调用机制 根据方法参数类型选择正确的方法 根据实际对象类型选择调用的重写方法
优点 性能较高,编译时就能确定调用方法 提高了灵活性和可扩展性,支持多态性

相关笔记

多态的载体是方法重写,完整规则见 重写与重载;多态在本篇讲"绑定时机",继承与多态 讲"整体图景",三篇互补。


⬅️ 方法重载和方法重写 🏠 00-Java ➡️ 访问控制修饰符