Java 多态

多态(Polymorphism)指"同一个方法调用,作用在不同对象上表现出不同行为"。它让代码面向父类编程、在运行时才决定调用哪个子类的实现,是面向对象三大特性之一,也是"开闭原则"的基石。

多态的三个条件

多态要同时满足三个条件:

  • 有继承关系:子类继承父类(或实现同一接口)。
  • 子类重写父类的方法。
  • 父类引用指向子类对象,如 Animal a = new Dog();。 经典"动物叫"例子:Animal 定规矩,Dog、Cat 各自重写 speak():
class Animal {
    void speak() { System.out.println("动物叫"); }
}
class Dog extends Animal {
    @Override void speak() { System.out.println("汪汪"); }
}
class Cat extends Animal {
    @Override void speak() { System.out.println("喵喵"); }
}
// —— 片段需放进 main 方法中运行 ——
Animal a1 = new Dog();       // 父类引用指向子类对象
Animal a2 = new Cat();
a1.speak();
a2.speak();
// 输出:汪汪
// 输出:喵喵

动态绑定:运行时才决定调谁

编译期只知道 a1 的静态类型是 Animal,真正执行哪个 speak() 要到运行时按对象实际类型绑定,这叫动态绑定,是多态的本质。"图形面积"同理,父类定规则、子类各算各的:

class Shape {
    double area() { return 0; }
}
class Circle extends Shape {
    double r;
    Circle(double r) { this.r = r; }
    @Override double area() { return 3.14 * r * r; }
}
class Rect extends Shape {
    double w, h;
    Rect(double w, double h) { this.w = w; this.h = h; }
    @Override double area() { return w * h; }
}
// —— 片段需放进 main 方法中运行 ——
Shape[] ss = { new Circle(2), new Rect(3, 4) };
for (Shape s : ss) System.out.println(s.area());
// 输出:12.56
// 输出:12.0

向上转型与向下转型

  • 向上转型:子类对象赋给父类引用,自动、安全;代价是只能调用父类声明的方法。
  • 向下转型:把父类引用还原成子类引用,必须强转 (子类) obj,类型不对会抛 ClassCastException。
  • 安全做法:先用 instanceof 判断类型,再转型。

沿用前面的动物类(片段需放进 main 方法中运行):

Animal a = new Dog();        // 向上转型
Dog d = (Dog) a;             // 向下转型:还原后可用子类独有能力
d.speak();

Cat c = new Cat();
// Dog d2 = (Dog) c;         // 编译能过,运行期抛 ClassCastException
if (a instanceof Dog) {      // instanceof 先判断
    System.out.println("a 确实是 Dog");
}
// 输出:汪汪
// 输出:a 确实是 Dog

多态参数与返回值

形参、返回值声明成父类类型,就能接收或返回任意子类对象。以后新增一种动物,调用方代码一行都不用改:

void show(Animal a) {        // 父类形参
    a.speak();
}
Animal makeDog() {           // 父类返回值
    return new Dog();
}

// —— 片段需放进 main 方法中运行 ——
show(new Dog());
show(new Cat());
// 输出:汪汪
// 输出:喵喵

多态的核心是"父类引用 + 方法重写 + 动态绑定":代码写在抽象层,行为由具体对象决定;新增子类不改旧代码,向下转型前先用 instanceof 兜底。

笔记加载中…