Skip to content

🎭 多态

多态概述

多态(Polymorphism)是面向对象编程的三大特性之一,它允许同一个接口使用不同的实现,提高了代码的灵活性和可扩展性。

多态的类型

  1. 编译时多态:方法重载(Overload)
  2. 运行时多态:方法重写(Override)+ 向上转型

多态的特点

  • 同一接口,不同实现:同一个方法调用,在不同对象上有不同行为
  • 提高可扩展性:新增子类不影响现有代码
  • 提高代码复用:通过父类引用统一处理子类对象

方法重载(编译时多态)

重载规则

  • 方法名相同
  • 参数列表不同(类型、数量、顺序)
  • 返回类型可以不同(但仅返回类型不同不能构成重载)

重载示例

java
public class Calculator {
    // 整数加法
    public int add(int a, int b) {
        return a + b;
    }
    
    // 浮点数加法(重载)
    public double add(double a, double b) {
        return a + b;
    }
    
    // 三个整数相加(重载)
    public int add(int a, int b, int c) {
        return a + b + c;
    }
    
    // 字符串连接(重载)
    public String add(String a, String b) {
        return a + b;
    }
}

// 使用
Calculator calc = new Calculator();
calc.add(1, 2);           // 调用 int add(int, int)
calc.add(1.0, 2.0);       // 调用 double add(double, double)
calc.add(1, 2, 3);        // 调用 int add(int, int, int)
calc.add("Hello", "World"); // 调用 String add(String, String)

方法重写(运行时多态)

运行时多态示例

java
// 父类
public class Animal {
    public void makeSound() {
        System.out.println("动物发出声音");
    }
    
    public void move() {
        System.out.println("动物在移动");
    }
}

// 子类1
public class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("狗叫: 汪汪汪");
    }
    
    @Override
    public void move() {
        System.out.println("狗在跑");
    }
}

// 子类2
public class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("猫叫: 喵喵喵");
    }
    
    @Override
    public void move() {
        System.out.println("猫在走");
    }
}

// 使用
Animal animal1 = new Dog();  // 向上转型
Animal animal2 = new Cat();  // 向上转型

animal1.makeSound();  // 输出: 狗叫: 汪汪汪(运行时多态)
animal1.move();       // 输出: 狗在跑

animal2.makeSound();  // 输出: 猫叫: 喵喵喵(运行时多态)
animal2.move();       // 输出: 猫在走

向上转型和向下转型

向上转型(Upcasting)

java
// 向上转型:子类对象赋值给父类引用
Animal animal = new Dog();  // Dog 向上转型为 Animal

// 可以调用父类中定义的方法
animal.makeSound();  // 调用 Dog 重写的方法
animal.move();       // 调用 Dog 重写的方法

// 不能调用子类特有的方法
// animal.bark();  // ❌ 编译错误

向下转型(Downcasting)

java
// 向下转型:父类引用转换为子类引用
Animal animal = new Dog();
Dog dog = (Dog) animal;  // 向下转型

// 现在可以调用子类特有的方法
dog.bark();  // ✅ 可以调用

instanceof 检查

java
Animal animal = new Dog();

// 使用 instanceof 检查类型
if (animal instanceof Dog) {
    Dog dog = (Dog) animal;  // 安全的向下转型
    dog.bark();
}

// 更安全的写法
if (animal instanceof Dog dog) {  // Java 14+ 模式匹配
    dog.bark();  // 自动转换
}

多态的应用

1. 统一接口处理

java
// 父类
public class Shape {
    public double calculateArea() {
        return 0;
    }
}

// 子类
public class Circle extends Shape {
    private double radius;
    
    public Circle(double radius) {
        this.radius = radius;
    }
    
    @Override
    public double calculateArea() {
        return Math.PI * radius * radius;
    }
}

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 double calculateArea() {
        return width * height;
    }
}

// 使用多态统一处理
Shape[] shapes = {
    new Circle(5),
    new Rectangle(4, 6),
    new Circle(3)
};

// 统一调用,不同对象执行不同实现
for (Shape shape : shapes) {
    System.out.println("面积: " + shape.calculateArea());
}

2. 方法参数多态

java
public class AnimalService {
    // 方法参数使用父类类型,可以接收任何子类对象
    public void feed(Animal animal) {
        animal.eat();
    }
    
    public void play(Animal animal) {
        animal.move();
    }
}

// 使用
AnimalService service = new AnimalService();
service.feed(new Dog());   // 可以传入 Dog 对象
service.feed(new Cat());   // 可以传入 Cat 对象
service.play(new Dog());   // 可以传入 Dog 对象

3. 方法返回多态

java
public class AnimalFactory {
    // 返回类型是父类,实际返回子类对象
    public Animal createAnimal(String type) {
        if ("dog".equals(type)) {
            return new Dog();
        } else if ("cat".equals(type)) {
            return new Cat();
        }
        return null;
    }
}

// 使用
AnimalFactory factory = new AnimalFactory();
Animal animal = factory.createAnimal("dog");  // 返回 Dog 对象
animal.makeSound();  // 调用 Dog 的方法

抽象类与多态

抽象类

java
// 抽象类
public abstract class Animal {
    protected String name;
    
    public Animal(String name) {
        this.name = name;
    }
    
    // 抽象方法:必须由子类实现
    public abstract void makeSound();
    
    // 普通方法:可以有实现
    public void eat() {
        System.out.println(name + " 正在吃东西");
    }
}

// 子类实现抽象方法
public class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }
    
    @Override
    public void makeSound() {
        System.out.println(name + " 叫: 汪汪汪");
    }
}

public class Cat extends Animal {
    public Cat(String name) {
        super(name);
    }
    
    @Override
    public void makeSound() {
        System.out.println(name + " 叫: 喵喵喵");
    }
}

接口与多态

java
// 接口
public interface Flyable {
    void fly();
}

public interface Swimmable {
    void swim();
}

// 实现接口
public class Duck implements Flyable, Swimmable {
    @Override
    public void fly() {
        System.out.println("鸭子飞");
    }
    
    @Override
    public void swim() {
        System.out.println("鸭子游泳");
    }
}

// 使用接口实现多态
Flyable flyable = new Duck();
flyable.fly();

Swimmable swimmable = new Duck();
swimmable.swim();

多态的完整示例

java
// 员工管理系统
public abstract class Employee {
    protected String name;
    protected int id;
    protected double baseSalary;
    
    public Employee(String name, int id, double baseSalary) {
        this.name = name;
        this.id = id;
        this.baseSalary = baseSalary;
    }
    
    // 抽象方法:计算工资(不同员工类型计算方式不同)
    public abstract double calculateSalary();
    
    // 普通方法
    public void displayInfo() {
        System.out.println("员工姓名: " + name);
        System.out.println("员工ID: " + id);
        System.out.println("基本工资: " + baseSalary);
        System.out.println("实际工资: " + calculateSalary());
    }
}

// 全职员工
public class FullTimeEmployee extends Employee {
    private double bonus;
    
    public FullTimeEmployee(String name, int id, double baseSalary, double bonus) {
        super(name, id, baseSalary);
        this.bonus = bonus;
    }
    
    @Override
    public double calculateSalary() {
        return baseSalary + bonus;
    }
}

// 兼职员工
public class PartTimeEmployee extends Employee {
    private int hours;
    private double hourlyRate;
    
    public PartTimeEmployee(String name, int id, double hourlyRate, int hours) {
        super(name, id, 0);  // 兼职员工没有基本工资
        this.hourlyRate = hourlyRate;
        this.hours = hours;
    }
    
    @Override
    public double calculateSalary() {
        return hourlyRate * hours;
    }
}

// 使用多态
public class EmployeeManagement {
    public static void main(String[] args) {
        // 创建不同类型的员工
        Employee[] employees = {
            new FullTimeEmployee("张三", 1, 10000, 2000),
            new PartTimeEmployee("李四", 2, 100, 80),
            new FullTimeEmployee("王五", 3, 8000, 1500)
        };
        
        // 统一处理,多态体现
        double totalSalary = 0;
        for (Employee emp : employees) {
            emp.displayInfo();  // 每个员工显示不同信息
            totalSalary += emp.calculateSalary();  // 不同员工工资计算方式不同
            System.out.println("---");
        }
        
        System.out.println("总工资支出: " + totalSalary);
    }
}

多态的优势

1. 提高代码可扩展性

java
// 添加新的员工类型,不需要修改现有代码
public class Contractor extends Employee {
    private double contractAmount;
    
    public Contractor(String name, int id, double contractAmount) {
        super(name, id, 0);
        this.contractAmount = contractAmount;
    }
    
    @Override
    public double calculateSalary() {
        return contractAmount;
    }
}

// 可以直接使用,无需修改 EmployeeManagement 类

2. 提高代码可维护性

java
// 修改某个子类的实现,不影响其他代码
public class FullTimeEmployee extends Employee {
    @Override
    public double calculateSalary() {
        // 修改计算逻辑,不影响调用方
        return baseSalary * 1.2 + bonus;  // 新逻辑
    }
}

3. 统一接口处理

java
// 一个方法可以处理所有子类对象
public void processEmployee(Employee emp) {
    emp.displayInfo();
    double salary = emp.calculateSalary();
    // 统一处理...
}

多态的注意事项

1. 方法重写的规则

java
// ✅ 正确的重写
public class Parent {
    public void method() { }
}

public class Child extends Parent {
    @Override
    public void method() { }  // 正确
}

// ❌ 错误:不是重写(参数不同)
public class Child extends Parent {
    public void method(int param) { }  // 这是重载,不是重写
}

2. 静态方法不能重写

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

public class Child extends Parent {
    public static void staticMethod() {  // 不是重写,是隐藏
        System.out.println("Child");
    }
}

// 使用
Parent p = new Child();
p.staticMethod();  // 输出: Parent(不是 Child)

3. 私有方法不能重写

java
public class Parent {
    private void privateMethod() { }  // 私有方法
}

public class Child extends Parent {
    // 这不是重写,是新的方法
    private void privateMethod() { }
}

最佳实践

1. 使用父类引用

java
// ✅ 好的做法:使用父类引用
List<Animal> animals = new ArrayList<>();
animals.add(new Dog());
animals.add(new Cat());

// ❌ 不好的做法:使用具体类型
List<Dog> dogs = new ArrayList<>();
List<Cat> cats = new ArrayList<>();

2. 优先使用接口

java
// ✅ 好的做法:使用接口
List<String> list = new ArrayList<>();  // 接口引用

// ❌ 不好的做法:使用具体类
ArrayList<String> list = new ArrayList<>();  // 具体类引用

3. 使用抽象类定义通用行为

java
// ✅ 好的做法:抽象类定义通用行为
public abstract class Animal {
    protected String name;
    
    public abstract void makeSound();  // 子类必须实现
    
    public void eat() {  // 通用行为
        System.out.println(name + " 正在吃");
    }
}

下一步

掌握了多态后,可以继续学习:


💡 提示:多态是面向对象编程的核心特性,理解多态有助于编写灵活、可扩展的代码