Skip to content

11.5 多态

多态的概念

多态(Polymorphism)是面向对象编程的三大特性之一,它允许不同对象对同一消息做出不同的响应。多态是通过方法重写和继承实现的。

多态的实现

在 Java 中,多态的实现主要通过以下方式:

  1. 继承:子类继承父类
  2. 方法重写:子类重写父类的方法
  3. 父类引用指向子类对象:使用父类类型的变量引用子类类型的对象

示例:基本多态

java
// 父类
public class Animal {
    public void makeSound() {
        System.out.println("Animal makes sound");
    }
}

// 子类
public class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Dog barks");
    }
}

// 子类
public class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Cat meows");
    }
}

// 测试类
public class PolymorphismExample {
    public static void main(String[] args) {
        // 父类引用指向子类对象
        Animal animal1 = new Dog();
        Animal animal2 = new Cat();
        
        // 多态:根据实际类型调用相应的方法
        animal1.makeSound(); // 输出 "Dog barks"
        animal2.makeSound(); // 输出 "Cat meows"
    }
}

多态的特点

  1. 编译时类型与运行时类型:编译时类型是变量声明的类型,运行时类型是变量实际引用的对象类型
  2. 方法调用:方法调用根据运行时类型决定,而不是编译时类型
  3. 向上转型:将子类对象赋值给父类引用,是自动的
  4. 向下转型:将父类引用转换为子类类型,需要显式转换

示例:编译时类型与运行时类型

java
public class PolymorphismExample {
    public static void main(String[] args) {
        // 编译时类型:Animal,运行时类型:Dog
        Animal animal = new Dog();
        
        // 调用的是 Dog 类的 makeSound 方法
        animal.makeSound();
        
        // 编译时类型:Animal,运行时类型:Cat
        animal = new Cat();
        
        // 调用的是 Cat 类的 makeSound 方法
        animal.makeSound();
    }
}

示例:多态的应用

示例 1:动物类

java
// 父类:Animal
public class Animal {
    public void makeSound() {
        System.out.println("Animal makes sound");
    }
    
    public void eat() {
        System.out.println("Animal eats");
    }
}

// 子类:Dog
public class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Dog barks");
    }
    
    @Override
    public void eat() {
        System.out.println("Dog eats bones");
    }
}

// 子类:Cat
public class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Cat meows");
    }
    
    @Override
    public void eat() {
        System.out.println("Cat eats fish");
    }
}

// 测试类
public class AnimalExample {
    public static void main(String[] args) {
        // 创建动物数组
        Animal[] animals = new Animal[3];
        animals[0] = new Animal();
        animals[1] = new Dog();
        animals[2] = new Cat();
        
        // 遍历数组,调用方法
        for (Animal animal : animals) {
            animal.makeSound();
            animal.eat();
            System.out.println();
        }
    }
}

示例 2:形状类

java
// 父类:Shape
public abstract class Shape {
    public abstract void draw();
    public abstract double calculateArea();
}

// 子类:Circle
public class Circle extends Shape {
    private double radius;
    
    public Circle(double radius) {
        this.radius = radius;
    }
    
    @Override
    public void draw() {
        System.out.println("Drawing a circle");
    }
    
    @Override
    public double calculateArea() {
        return Math.PI * radius * radius;
    }
}

// 子类:Rectangle
public class Rectangle extends Shape {
    private double width;
    private double height;
    
    public Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }
    
    @Override
    public void draw() {
        System.out.println("Drawing a rectangle");
    }
    
    @Override
    public double calculateArea() {
        return width * height;
    }
}

// 测试类
public class ShapeExample {
    public static void main(String[] args) {
        // 创建形状数组
        Shape[] shapes = new Shape[2];
        shapes[0] = new Circle(5);
        shapes[1] = new Rectangle(4, 6);
        
        // 遍历数组,调用方法
        for (Shape shape : shapes) {
            shape.draw();
            System.out.println("Area: " + shape.calculateArea());
            System.out.println();
        }
    }
}

示例 3:员工类

java
// 父类:Employee
public class Employee {
    protected String name;
    
    public Employee(String name) {
        this.name = name;
    }
    
    public void work() {
        System.out.println(name + " is working");
    }
    
    public double calculateSalary() {
        return 0.0;
    }
}

// 子类:Manager
public class Manager extends Employee {
    private double bonus;
    
    public Manager(String name, double bonus) {
        super(name);
        this.bonus = bonus;
    }
    
    @Override
    public void work() {
        System.out.println(name + " is managing the team");
    }
    
    @Override
    public double calculateSalary() {
        return 8000 + bonus;
    }
}

// 子类:Developer
public class Developer extends Employee {
    private String programmingLanguage;
    
    public Developer(String name, String programmingLanguage) {
        super(name);
        this.programmingLanguage = programmingLanguage;
    }
    
    @Override
    public void work() {
        System.out.println(name + " is coding in " + programmingLanguage);
    }
    
    @Override
    public double calculateSalary() {
        return 6000;
    }
}

// 测试类
public class EmployeeExample {
    public static void main(String[] args) {
        // 创建员工数组
        Employee[] employees = new Employee[3];
        employees[0] = new Employee("John");
        employees[1] = new Manager("Jane", 2000);
        employees[2] = new Developer("Bob", "Java");
        
        // 遍历数组,调用方法
        for (Employee employee : employees) {
            employee.work();
            System.out.println("Salary: " + employee.calculateSalary());
            System.out.println();
        }
    }
}

多态的优势

  1. 代码灵活性:通过多态,可以编写更灵活、更通用的代码
  2. 代码可扩展性:当添加新的子类时,不需要修改现有代码
  3. 代码可维护性:将代码逻辑集中在父类,子类只需实现自己的特有逻辑
  4. 代码复用:通过继承和多态,实现代码复用

示例:多态的优势

java
// 父类:Animal
public class Animal {
    public void makeSound() {
        System.out.println("Animal makes sound");
    }
}

// 子类:Dog
public class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Dog barks");
    }
}

// 子类:Cat
public class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Cat meows");
    }
}

// 新增子类:Bird
public class Bird extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Bird sings");
    }
}

// 测试类
public class PolymorphismAdvantage {
    // 通用方法,接受任何 Animal 类型
    public static void makeAnimalSound(Animal animal) {
        animal.makeSound();
    }
    
    public static void main(String[] args) {
        // 调用通用方法
        makeAnimalSound(new Dog());
        makeAnimalSound(new Cat());
        makeAnimalSound(new Bird()); // 新增子类,不需要修改现有代码
    }
}

向上转型和向下转型

向上转型

向上转型是将子类对象赋值给父类引用,是自动的。

语法:

java
父类类型 变量名 = new 子类类型();

示例:

java
Animal animal = new Dog(); // 向上转型

向下转型

向下转型是将父类引用转换为子类类型,需要显式转换。

语法:

java
子类类型 变量名 = (子类类型) 父类引用;

示例:

java
Animal animal = new Dog();
Dog dog = (Dog) animal; // 向下转型

instanceof 运算符

在向下转型之前,通常使用 instanceof 运算符检查对象的实际类型,避免类型转换错误。

语法:

java
对象 instanceof 类型

示例:

java
Animal animal = new Dog();
if (animal instanceof Dog) {
    Dog dog = (Dog) animal;
    // 调用 Dog 类的特有方法
}

示例:向下转型

java
// 父类:Animal
public class Animal {
    public void makeSound() {
        System.out.println("Animal makes sound");
    }
}

// 子类:Dog
public class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Dog barks");
    }
    
    // Dog 类的特有方法
    public void fetch() {
        System.out.println("Dog fetches the ball");
    }
}

// 子类:Cat
public class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Cat meows");
    }
    
    // Cat 类的特有方法
    public void scratch() {
        System.out.println("Cat scratches the furniture");
    }
}

// 测试类
public class DowncastingExample {
    public static void main(String[] args) {
        // 向上转型
        Animal animal1 = new Dog();
        Animal animal2 = new Cat();
        
        // 调用父类方法
        animal1.makeSound();
        animal2.makeSound();
        
        // 向下转型
        if (animal1 instanceof Dog) {
            Dog dog = (Dog) animal1;
            dog.fetch();
        }
        
        if (animal2 instanceof Cat) {
            Cat cat = (Cat) animal2;
            cat.scratch();
        }
    }
}

多态的实现机制

Java 中的多态是通过方法表实现的。每个类都有一个方法表,记录了该类的所有方法。当调用一个方法时,Java 虚拟机会根据对象的实际类型查找相应的方法表,然后调用对应的方法。

方法调用的过程

  1. 编译时:检查方法是否存在于编译时类型中
  2. 运行时:根据对象的实际类型,调用相应的方法

常见问题

1. 方法不存在

症状:编译错误:The method methodName() is undefined for the type Parent

解决方案:确保调用的方法在父类中存在

示例:

java
public class Parent {
    public void method1() {
    }
}

public class Child extends Parent {
    public void method2() {
    }
}

public class Example {
    public static void main(String[] args) {
        Parent parent = new Child();
        parent.method1(); // 正确:method1 在父类中存在
        // parent.method2(); // 错误:method2 在父类中不存在
    }
}

2. 类型转换错误

症状:运行时错误:ClassCastException

解决方案:在向下转型之前,使用 instanceof 运算符检查对象的实际类型

示例:

java
public class Example {
    public static void main(String[] args) {
        Animal animal = new Dog();
        // 错误:animal 的实际类型是 Dog,不能转换为 Cat
        // Cat cat = (Cat) animal;
        
        // 正确:使用 instanceof 检查
        if (animal instanceof Cat) {
            Cat cat = (Cat) animal;
        } else {
            System.out.println("animal is not a Cat");
        }
    }
}

3. 静态方法不支持多态

症状:静态方法调用的是编译时类型的方法,而不是运行时类型的方法

解决方案:静态方法不支持多态,它们属于类,不属于对象

示例:

java
public class Parent {
    public static void staticMethod() {
        System.out.println("Parent static method");
    }
}

public class Child extends Parent {
    public static void staticMethod() {
        System.out.println("Child static method");
    }
}

public class Example {
    public static void main(String[] args) {
        Parent parent = new Child();
        parent.staticMethod(); // 输出 "Parent static method",静态方法不支持多态
    }
}

最佳实践

  1. 使用抽象类和接口:通过抽象类和接口定义共同的行为
  2. 合理使用向上转型:将子类对象赋值给父类引用,提高代码的灵活性
  3. 谨慎使用向下转型:在向下转型之前,使用 instanceof 检查对象的实际类型
  4. 理解多态的实现机制:了解方法表和方法调用的过程
  5. 设计良好的继承层次:合理设计类的继承层次,提高代码的可维护性

总结

多态是面向对象编程的三大特性之一,它允许不同对象对同一消息做出不同的响应。多态是通过方法重写和继承实现的。

多态的实现方式:

  • 继承:子类继承父类
  • 方法重写:子类重写父类的方法
  • 父类引用指向子类对象:使用父类类型的变量引用子类类型的对象

多态的优势:

  • 代码灵活性:编写更灵活、更通用的代码
  • 代码可扩展性:添加新的子类时,不需要修改现有代码
  • 代码可维护性:将代码逻辑集中在父类
  • 代码复用:通过继承和多态,实现代码复用

通过合理使用多态,可以提高代码的灵活性、可扩展性和可维护性。

© 2026 编程马·菜鸟教程 版权所有