多态底层原理的核心是JVM的虚方法表(vtable)机制:类加载时静态构建vtable,存储非private/static/final实例方法的入口地址;运行时根据对象实际类型查vtable对应槽位跳转执行。

多态底层原理的核心,是 JVM 的虚方法表(vtable)机制和运行时动态绑定。面试时不能只说“编译看左、运行看右”,要讲清楚 JVM 怎么做到的。
多态依赖虚方法表(vtable)
每个类在类加载阶段,JVM 都会为其生成一张虚方法表,里面按固定顺序存放该类所有可被重写(非 private、static、final)的实例方法的入口地址。
- 父类 Animal 的 vtable 包含 makeSound() 方法的地址,指向 Animal 类中该方法的字节码
- 子类 Dog 加载时,也会生成自己的 vtable;其中 makeSound() 条目被替换为 Dog 类中重写后的方法地址
- 调用 animal.makeSound() 时,JVM 不查 animal 变量声明类型(Animal),而是根据对象实际类型(Dog)找到其 vtable,再按索引定位到对应方法执行
静态方法和字段不参与多态
因为它们不进 vtable,也不依赖对象实例:
- 静态方法绑定发生在编译期,调用的是引用变量的声明类型所对应的类中的 static 方法
- 字段访问也看编译时类型 —— 即使 Dog 重写了 Animal 的 public String name,Animal a = new Dog(); a.name 访问的是 Animal 类里的 name 字段,不是 Dog 的
向上转型是多态的前提,但本质是引用类型转换
Animal a = new Dog(); 这行代码做了两件事:
立即学习“Java免费学习笔记(深入)”;
- 在堆上创建 Dog 实例,对象头里记录它的实际 class 元数据(含 Dog 的 vtable 地址)
- a 这个引用变量存储的是该对象的内存地址,但编译器只允许它调用 Animal 中定义的方法(编译检查)
为什么 final、private、static 方法不能被重写
这些方法不具备“运行时可替换性”:
- private 方法对外不可见,子类根本无法重写,只能定义同名新方法(与父类无关)
- static 方法属于类,不是对象,调用直接绑定到类符号引用,不走 vtable 查找
- final 方法在字节码层面被标记为 ACC_FINAL,JVM 禁止子类覆盖,也就不会出现在子类 vtable 的重写位置


















