Java多态执行版本由JVM运行时根据对象实际类型动态决定,需满足:非static、非private、非final且被子类@Override重写;编译期仅检查方法存在性并生成invokevirtual指令,运行期通过虚方法表查表绑定。

Java 中多态的执行版本,是在运行时由 JVM 根据对象的实际类型动态决定的,这个过程依赖于动态绑定机制。关键不在于变量怎么声明,而在于 new 出来的是哪个类的实例,且该方法必须满足可重写的条件。
哪些方法能触发动态绑定
只有满足以下全部条件的方法调用,才会走动态绑定路径:
- 是实例方法(非 static)
- 不是 private(否则子类不可见,谈不上重写)
- 不是 final(否则禁止重写)
- 在子类中确实被 @Override 重写了
例如:Animal a = new Dog(); a.sound(); 能执行 Dog.sound(),前提是 sound() 是 public/protected 实例方法,且 Dog 类里有对应重写。
JVM 运行时怎么找对方法
当执行 a.sound() 时,JVM 不会直接跳转到某个固定地址,而是按步骤查表定位:
立即学习“Java免费学习笔记(深入)”;
- 读取对象头中的类元数据指针,确认实际类型是
Dog - 定位到
Dog类的方法表(vtable) - 按方法签名(如
sound())在表中查找入口地址 - 若
Dog表中有该方法,就调用它;否则沿继承链向上查,直到Animal
这个过程发生在每次调用时,但 vtable 是类加载时就构建好的,所以开销可控。
编译期只做“合法性检查”
编译器对 a.sound() 只做两件事:
- 确认
Animal类中存在可访问的sound()方法(否则编译失败) - 生成
invokevirtual Animal.sound字节码指令,不写死目标地址
真正绑定哪个具体实现,完全交给运行时——哪怕 a 指向 Cat 或 Bird,只要它们重写了 sound(),就会各自执行自己的版本。
怎么验证你正在用动态绑定
遇到不确定时,可以快速判断:
- 在方法体内打印
this.getClass().getName(),输出的就是真实执行类名 - 把方法改成
static,如果输出变成父类名,说明原来走的是动态绑定 - 用
javap -v查字节码,看到invokevirtual指令,基本就是动态绑定


















