Java多态方法调用执行子类重写版本,前提是方法非static、非private、非final且被子类@Override重写;编译期检查方法存在性并生成invokevirtual指令,运行时JVM根据对象实际类型查虚方法表动态绑定。

Java 中多态调用方法时,执行哪个版本由运行时对象的实际类型决定,而不是引用变量的声明类型。关键前提是该方法必须是可被重写的实例方法——即非 static、非 private、非 final,且在子类中确实被重写(@Override)。
看 new 的是谁,但前提是方法被重写了
语句如 Animal a = new Dog(); a.sound(); 最终执行的是 Dog.sound(),因为:
- 对象在堆中真实类型是
Dog,JVM 在运行时依据这个类型查找方法 - 如果
Dog类重写了sound(),就调用它的版本;如果没有重写,就沿继承链向上找,最终执行Animal.sound() - 所以“new 的是哪个类”只是必要条件,不是充分条件——没重写,就不会执行子类逻辑
编译期只检查语法,运行期才定具体方法
编译器只做两件事:
- 确认
a.sound()在Animal类中存在(否则编译失败) - 生成
invokevirtual Animal.sound字节码指令,不硬编码跳转地址
真正的方法绑定发生在运行时:JVM 读取对象头中的类元数据指针,定位到 Dog 类的虚方法表(vtable),按方法签名查表,拿到 Dog.sound 的实际入口地址后跳转执行。
立即学习“Java免费学习笔记(深入)”;
哪些方法不走这套流程?
以下情况不参与动态绑定,也就没有多态效果:
-
静态方法:调用看引用类型,
Animal a = new Dog(); a.staticMethod()执行的是Animal.staticMethod -
私有方法:隐式
final,编译期绑定,子类里同名方法只是新方法,不是重写 -
构造器和
final方法:不可重写,自然不触发动态分派 - 重载(overload)方法:选择发生在编译期,依据参数的静态类型,与运行时对象无关
快速验证你调用的到底是不是多态版本
遇到不确定时,可用这几个办法现场确认:
- 在被调用方法里加
System.out.println(this.getClass().getName());,输出的就是真实执行类 - 把方法改成
static,如果行为变了(比如输出变成父类名),说明原来走的是动态绑定 - 用
javap -v查字节码,看到invokevirtual指令,基本就是多态调用


















