Java重写方法实现运行时动态绑定,核心是继承+方法签名一致+非private/static/final修饰,且通过父类引用调用子类对象;JVM依实际对象类型查vtable决定执行版本。

Java 中重写(Override)方法实现运行时动态绑定,核心在于 继承 + 方法签名一致 + 非 private / static / final 修饰,且调用发生在父类引用指向子类对象的场景下。JVM 在运行时根据实际对象类型(而非引用类型)决定调用哪个版本的方法,这就是动态绑定(也称晚期绑定、运行时多态)。
动态绑定发生的前提条件
只有同时满足以下几点,重写的方法才会触发动态绑定:
- 存在继承关系:子类 extends 父类(或实现接口)
- 子类中定义了与父类同名、同参数列表、同返回类型(或协变返回类型)的方法
- 该方法在父类中是 非 private、非 static、非 final 的(private 方法不可被重写,static 是静态绑定,final 禁止重写)
- 调用方式是通过父类类型引用访问该方法,但实际指向的是子类实例,例如:
Animal a = new Dog(); a.sound();
JVM 如何在运行时确定调用哪个方法
JVM 为每个类维护一个虚方法表(vtable),表中存放该类所有可被动态绑定的实例方法的实际入口地址。当执行如 a.sound() 这样的调用时:
- 编译期只检查引用类型(
Animal)中是否存在sound()方法(静态检查,确保编译通过) - 运行期 JVM 查看
a实际指向的对象所属类(这里是Dog),定位其 vtable - 在
Dog的 vtable 中查找sound()对应的函数指针,跳转执行子类版本
常见误区与验证技巧
容易误以为“重写了就一定动态绑定”,其实关键在调用上下文:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
-
错例:直接用子类引用调用,如
Dog d = new Dog(); d.sound();—— 虽然仍是重写,但编译器可能优化为单态调用,不体现多态价值 -
错例:父类方法是
static,子类“同名方法”只是隐藏(hiding),属于编译期绑定,和对象实际类型无关 -
验证方法:在父类方法中打印
this.getClass().getSimpleName(),运行时输出的是子类名,说明真正执行的是子类逻辑
一个典型可运行示例
下面代码能清晰体现动态绑定效果:
class Animal { void makeSound() { System.out.println("Animal sound"); } }
class Cat extends Animal { void makeSound() { System.out.println("Meow"); } }
class Dog extends Animal { void makeSound() { System.out.println("Woof"); } }
public class Main {
public static void main(String[] args) {
Animal a1 = new Cat();
Animal a2 = new Dog();
a1.makeSound(); // 输出 Meow
a2.makeSound(); // 输出 Woof
}
}
两次调用的引用类型都是 Animal,但输出不同——JVM 在运行时依据 a1 和 a2 实际所指对象的真实类型,分别调用了 Cat.makeSound() 和 Dog.makeSound()。

















