Java - 多态(Polymorphism)

更新于 2025-12-27

多态是面向对象编程(OOP)中的一个核心概念,指的是一个对象可以呈现出多种形式的能力。在 Java 中,多态允许我们通过同一个方法名执行多种不同的操作。

任何能够通过多个 IS-A 测试的 Java 对象都被认为是多态的。由于所有 Java 对象都继承自 Object 类,因此每个 Java 对象至少可以通过两个 IS-A 测试:它自身的类型和 Object 类型,所以所有 Java 对象本质上都是多态的


Java 中多态的使用

在面向对象编程中,多态最常见的用法是:使用父类的引用变量来引用子类的对象

需要记住以下几点:

  • 访问对象的唯一方式是通过引用变量
  • 引用变量只能有一种类型,一旦声明后,其类型不能更改。
  • 如果引用变量未被声明为 final,它可以被重新赋值为其他对象。
  • 引用变量的类型决定了它可以调用哪些方法。
  • 引用变量可以指向其声明类型或其任何子类型的对象。
  • 引用变量可以声明为类类型或接口类型。

Java 多态示例

考虑以下代码:

public interface Vegetarian {}
public class Animal {}
public class Deer extends Animal implements Vegetarian {}

此时,Deer 类被认为是多态的,因为它满足多重“IS-A”关系:

  • Deer IS-A Animal
  • Deer IS-A Vegetarian
  • Deer IS-A Deer
  • Deer IS-A Object

因此,以下声明都是合法的:

Deer d = new Deer();
Animal a = d;
Vegetarian v = d;
Object o = d;

上述所有引用变量 davo 都指向堆内存中的同一个 Deer 对象。

示例代码

interface Vegetarian {}
class Animal {}
public class Deer extends Animal implements Vegetarian {
    public static void main(String[] args) {
        Deer d = new Deer();
        Animal a = d;
        Vegetarian v = d;
        Object o = d;

        System.out.println(d instanceof Deer);      // true
        System.out.println(a instanceof Deer);      // true
        System.out.println(v instanceof Deer);      // true
        System.out.println(o instanceof Deer);      // true
    }
}

输出:

true
true
true
true

Java 多态的类型

Java 中的多态分为两种:

  1. 编译时多态(Compile Time Polymorphism)
  2. 运行时多态(Run Time Polymorphism)

1. 编译时多态(静态多态)

也称为静态多态,通过**方法重载(Method Overloading)**实现。

示例:编译时多态

public class Main {
    // 两个整数相加
    public int addition(int x, int y) {
        return x + y;
    }

    // 三个整数相加
    public int addition(int x, int y, int z) {
        return x + y + z;
    }

    // 两个 double 相加
    public double addition(double x, double y) {
        return x + y;
    }

    public static void main(String[] args) {
        Main number = new Main();

        int res1 = number.addition(444, 555);
        System.out.println("两个整数相加: " + res1);

        int res2 = number.addition(333, 444, 555);
        System.out.println("三个整数相加: " + res2);

        double res3 = number.addition(10.15, 20.22);
        System.out.println("两个 double 相加: " + res3);
    }
}

输出:

两个整数相加: 999
三个整数相加: 1332
两个 double 相加: 30.369999999999997

方法重载是在编译期根据参数列表决定调用哪个方法。


2. 运行时多态(动态多态)

也称为动态方法分派(Dynamic Method Dispatch),通过**方法重写(Method Overriding)**实现。

示例:运行时多态

class Vehicle {
    public void displayInfo() {
        System.out.println("Some vehicles are there.");
    }
}

class Car extends Vehicle {
    @Override
    public void displayInfo() {
        System.out.println("I have a Car.");
    }
}

class Bike extends Vehicle {
    @Override
    public void displayInfo() {
        System.out.println("I have a Bike.");
    }
}

public class Main {
    public static void main(String[] args) {
        Vehicle v1 = new Car();  // 向上转型
        Vehicle v2 = new Bike(); // 向上转型

        v1.displayInfo(); // 调用 Car 的 displayInfo()
        v2.displayInfo(); // 调用 Bike 的 displayInfo()
    }
}

输出:

I have a Car.
I have a Bike.

尽管引用类型是 Vehicle,但 JVM 在运行时根据实际对象类型调用相应子类的方法。


虚方法与运行时多态

Java 中所有非 private、非 static、非 final 的实例方法本质上都是虚方法(Virtual Methods),支持运行时多态。

示例:虚方法调用

// Employee.java
class Employee {
    private String name;
    private String address;
    private int number;

    public Employee(String name, String address, int number) {
        System.out.println("Constructing an Employee");
        this.name = name;
        this.address = address;
        this.number = number;
    }

    public void mailCheck() {
        System.out.println("Mailing a check to " + this.name + " " + this.address);
    }

    public String getName() { return name; }
    public String getAddress() { return address; }
    public int getNumber() { return number; }
}

// Salary.java
class Salary extends Employee {
    private double salary;

    public Salary(String name, String address, int number, double salary) {
        super(name, address, number);
        setSalary(salary);
    }

    @Override
    public void mailCheck() {
        System.out.println("Within mailCheck of Salary class");
        System.out.println("Mailing check to " + getName() + " with salary " + salary);
    }

    public void setSalary(double newSalary) {
        if (newSalary >= 0.0) salary = newSalary;
    }

    public double getSalary() { return salary; }
}

// VirtualDemo.java
public class VirtualDemo {
    public static void main(String[] args) {
        Salary s = new Salary("Mohd Mohtashim", "Ambehta, UP", 3, 3600.00);
        Employee e = new Salary("John Adams", "Boston, MA", 2, 2400.00);

        System.out.println("使用 Salary 引用调用 mailCheck --");
        s.mailCheck();

        System.out.println("\n使用 Employee 引用调用 mailCheck --");
        e.mailCheck();
    }
}

输出:

Constructing an Employee
Constructing an Employee
使用 Salary 引用调用 mailCheck --
Within mailCheck of Salary class
Mailing check to Mohd Mohtashim with salary 3600.0

使用 Employee 引用调用 mailCheck --
Within mailCheck of Salary class
Mailing check to John Adams with salary 2400.0

即使 eEmployee 类型的引用,JVM 在运行时仍会调用 Salary 类中重写的 mailCheck() 方法。这种机制称为虚方法调用(Virtual Method Invocation)


总结

特性 编译时多态 运行时多态
别名 静态多态 动态多态
实现方式 方法重载(Overloading) 方法重写(Overriding)
决策时机 编译期 运行期
依据 参数列表(数量、类型、顺序) 实际对象类型
示例 add(int a, int b) vs add(double a, double b) Animal a = new Dog(); a.speak();

多态是 Java 实现灵活性可扩展性的关键机制,广泛应用于框架设计、插件系统和接口编程中。