多态使同一代码可处理不同子类对象,核心是“编译看引用类型,运行看实际类型”;需满足继承(或实现接口)、子类重写父类实例方法、父类引用指向子类对象三个条件;接口多态更灵活,应避免滥用instanceof。

多态让同一段代码能处理不同子类对象
Java中多态的核心是「编译看引用类型,运行看实际类型」。这意味着你写 Animal a = new Dog();,调用 a.speak() 时,实际执行的是 Dog.speak(),而不是 Animal.speak()(假设已重写)。这种机制让上层逻辑无需感知具体子类,比如一个 feed(Animal animal) 方法,传入 Dog、Cat 或未来新增的 Parrot 都能正常工作——只要它们都继承自 Animal 并实现了 speak()。
必须满足三个条件才能触发多态行为
缺一不可,否则看似写了多态代码,实际不会生效:
- 有继承关系(或实现接口),如
class Dog extends Animal - 子类重写父类方法(必须是
@Override的实例方法;static、private、final方法不参与多态) - 使用父类(或接口)类型引用指向子类对象,如
Animal a = new Dog();,而不是Dog d = new Dog();
常见错误:把 new Dog() 赋给 Dog 类型变量后传入方法,表面看是“多态调用”,实则只是普通方法调用,编译期就绑定了,后续加新子类也不会自动适配。
接口多态比继承多态更灵活、更常用
用接口定义行为契约,多个无关类可实现同一接口,避免单继承限制。例如定义 interface Drawable { void draw(); },Circle、Text、Image 各自实现,上层渲染器只需操作 Drawable 列表:
立即学习“Java免费学习笔记(深入)”;
List<Drawable> elements = Arrays.asList(new Circle(), new Text(), new Image());
for (Drawable d : elements) {
d.draw(); // 自动调用各自实现
}
这样新增 SVG 类只需实现 Drawable,无需修改渲染逻辑。而基于继承的多态容易陷入“为复用而继承”的陷阱,导致类层次臃肿。
运行时类型检查和强制转换要谨慎
多态带来灵活性的同时,也隐藏了类型信息。如果确实需要调用子类特有方法(如 Dog.bark()),必须先用 instanceof 检查再强制转换:
if (animal instanceof Dog) {
((Dog) animal).bark();
}
但频繁出现这种代码,往往说明设计有问题:要么该行为应提升到父类/接口,要么职责划分不清。过度依赖 instanceof 会削弱多态价值,也让扩展变脆弱——每加一个子类,就得补一堆类型判断。
真正难的不是写出多态语法,而是识别哪些行为该抽象、哪些差异该封装、哪些类型检查其实是设计信号。写完 if (x instanceof Y),最好停一下,想想能不能用策略模式或访问者模式绕开它。








