多态(Polymorphism)是面向对象编程(OOP)的三大特性之一(另外两个是 封装 和 继承),它允许 同一个行为具有不同的表现形式。在 Java 中,多态主要通过 方法重写(Override) 和 接口/抽象类 实现。
多态的核心概念
多态的核心思想
- 同一方法在不同对象上有不同的实现。
- 父类引用可以指向子类对象(向上转型)
- 运行时决定调用哪个方法(动态绑定)
多态的分类
编译时多态(静态多态)
- 通过方法重载(Overload)实现
- 在编译时就能确定调用哪个方法
- 示例:
void print(int a) { ... } void print(String s) { ... } // 方法重载
运行时多态(动态多态)
- 通过方法重写(Override)实现
- 在运行时根据对象的实际类型决定调用哪个方法
- 示例:
class Animal { void sound() { ... } } class Dog extends Animal { @Override void sound() { System.out.println("汪汪!"); } }
多态的实现方式
方法重写(Override)
子类重写父类的方法,运行时调用子类的方法:
class Animal {
void sound() {
System.out.println("动物叫");
}
}
class Dog extends Animal {
@Override
void sound() {
System.out.println("汪汪!");
}
}
public class Main {
public static void main(String[] args) {
Animal myDog = new Dog(); // 父类引用指向子类对象
myDog.sound(); // 输出:"汪汪!"(调用子类方法)
}
}
运行结果:
汪汪!
接口多态
接口的引用可以指向实现类的对象:
interface Flyable {
void fly();
}
class Bird implements Flyable {
@Override
public void fly() {
System.out.println("鸟儿飞翔");
}
}
public class Main {
public static void main(String[] args) {
Flyable myBird = new Bird(); // 接口引用指向实现类对象
myBird.fly(); // 输出:"鸟儿飞翔"
}
}
抽象类多态
抽象类的引用可以指向子类对象:
abstract class Shape {
abstract void draw();
}
class Circle extends Shape {
@Override
void draw() {
System.out.println("画一个圆形");
}
}
public class Main {
public static void main(String[] args) {
Shape myShape = new Circle(); // 抽象类引用指向子类对象
myShape.draw(); // 输出:"画一个圆形"
}
}
多态的特点
向上转型(Upcasting)
父类引用指向子类对象:
Animal myDog = new Dog(); // 向上转型
- 优点:提高代码灵活性,可以统一处理不同子类对象
- 限制:只能调用父类中定义的方法,不能调用子类特有的方法
向下转型(Downcasting)
将父类引用强制转回子类类型:
Animal animal = new Dog();
Dog dog = (Dog) animal; // 向下转型(需确保 animal 实际是 Dog 类型)
- 风险:如果转型错误(如animal实际是Cat),会抛出ClassCastException
- 解决方案:先用instanceof检查:
if (animal instanceof Dog) { Dog dog = (Dog) animal; }
多态的应用场景
方法参数多态
方法可以接受父类/接口类型,实际传入子类对象:
void makeSound(Animal animal) {
animal.sound(); // 动态绑定
}
makeSound(new Dog()); // 输出:"汪汪!"
makeSound(new Cat()); // 输出:"喵喵!"
集合存储多态
集合(如List)可以存储不同子类对象:
List<Animal> animals = new ArrayList<>();
animals.add(new Dog());
animals.add(new Cat());
工厂模式
返回接口/父类类型,隐藏具体实现:
Animal getAnimal(String type) {
if ("dog".equals(type)) return new Dog();
else return new Cat();
}
策略模式
通过接口多态动态切换算法:
interface Payment { void pay(); }
class Alipay implements Payment { ... }
class WechatPay implements Payment { ... }
Payment payment = new Alipay();
payment.pay(); // 使用支付宝支付
多态vs重载(Overload)
特性 | 多态(Override) | 重载(Overload) |
---|---|---|
绑定时机 | 运行时(动态绑定) | 编译时(静态绑定) |
方法签名 | 必须相同(方法名、参数、返回类型) | 必须不同(参数类型或数量不同) |
应用场景 | 子类扩展父类行为 | 同一方法名处理不同输入 |
总结
- 多态的本质:统一方法在不同对象上有不同表现
- 实现方式:方法重写(Override)、接口、抽象类
- 核心机制:向上转型 + 动态绑定
- 优点:提高代码扩展性、降低耦合
- 典型应用:框架设计(如Spring的依赖注入)、策略模式、工厂模式
练习
最后让我们用一个小测验练习一下多态的使用
让我们分析一下图中右侧Test方法中的输出的结果都是些什么
类继承关系
通过上文的学习我们经过缜密的分析可以得到结果
确定一下最终输出结果
1---A and A
2---A and A
3---A and D
4---B and A
5---B and A
6---A and D
7---B and A
8---B and A
9---A and D