Java多态通过方法重写实现运行时动态绑定,编译时看引用类型、运行时看实际对象类型;满足方法名参数相同、返回类型协变、访问修饰符不更严格、非static/final/private、存在继承关系等条件才能触发多态。

Java 多态通过方法重写(Override)实现运行时动态绑定,核心在于:编译时看引用类型,运行时看实际对象类型。只要满足重写规则,JVM 会在调用时自动查找到子类中真正要执行的方法版本。
重写必须满足的基本条件
只有符合以下全部条件,才算有效重写,才能触发多态行为:
- 方法名、参数列表(类型、个数、顺序)完全相同
- 返回类型是协变的(子类方法返回类型可为父类返回类型的子类型,如
Object→String) - 访问修饰符不能更严格(如父类
protected,子类不能用private) - 不能重写
static、final或private方法(它们不参与多态) - 子类与父类必须存在继承关系(或实现接口)
运行时如何决定调用哪个方法
JVM 在执行 invokevirtual 指令时,会根据栈帧中对象的实际类型(即 new 出来的那个类),去该类的方法区查找对应方法表(vtable)。如果子类重写了该方法,就直接跳转到子类版本;否则沿继承链向上查找,直到找到首个非抽象实现。
例如:
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
Animal a = new Dog();
a.sound(); // 实际调用 Dog.sound(),不是 Animal.sound()
这里 a 的编译时类型是 Animal,但运行时类型是 Dog,JVM 查 Dog 类的方法表,发现 sound() 被重写,于是执行子类逻辑。
容易忽略的关键细节
-
静态方法不支持多态:即使子类定义了同名同参的
static方法,调用仍取决于引用类型(编译期绑定) - 成员变量不参与多态:访问字段时永远依据引用类型,不会动态切换
- 构造器中调用被重写方法要小心:子类对象尚未初始化完成,此时调用可能访问到未初始化的子类字段,引发意外行为
- 重载(Overload)发生在编译期:和多态无关,它只看参数类型(静态类型),不是运行时行为
验证多态是否生效的小技巧
在方法内打印 this.getClass().getSimpleName(),能直观看到当前执行的是哪个类的实例:
class Animal { void show() { System.out.println(this.getClass().getSimpleName()); } }
class Cat extends Animal {}
Animal x = new Cat(); x.show(); // 输出 "Cat"
这说明 JVM 确实把调用路由到了子类对象上,多态已生效。

















