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 兜底。