Java多态靠继承或接口实现、方法重写、父类引用指向子类对象三者协同实现,底层依赖JVM虚方法表(vtable)和invokevirtual指令完成运行时动态绑定。

Java 中多态靠继承(或接口实现)+ 方法重写 + 父类引用指向子类对象这三者协同实现,底层依赖 JVM 的虚方法表(Method Table)和 invokevirtual 指令完成运行时动态绑定。
多态的三个必要条件
缺一不可:
- 存在继承关系(子类 extends 父类)或实现关系(类 implements 接口)
- 子类重写了父类的非 private、非 static、非 final 的实例方法
- 使用父类类型声明变量,但实际指向子类对象,例如:
Animal a = new Dog();
动态绑定是怎么发生的
当执行 a.makeSound() 这类调用时,JVM 不在编译期决定调哪个方法,而是在运行期根据 对象的实际类型 查找并跳转到对应实现。这个过程靠两样东西支撑:
-
虚方法表(vtable):每个类加载进方法区后,JVM 为其生成一张方法表,按固定顺序存放所有可被重写的方法地址。比如
Dog类的方法表中,makeSound项存的是Dog.makeSound的入口地址 -
invokevirtual 指令:字节码中该指令会先获取对象实际类型,再查该类型的虚方法表,按方法在表中的索引(偏移量)定位具体实现。哪怕变量声明为
Animal,只要运行时是Dog实例,就走Dog表里的地址
为什么有些方法不参与多态
不是所有方法都支持动态绑定。以下情况走的是静态绑定(编译期就定死):
立即学习“Java免费学习笔记(深入)”;
-
static方法:通过invokestatic调用,只看引用类型,不看实际对象 -
private、final和构造方法:用invokespecial调用,同样依据引用类型解析,无法被重写,自然无多态 - 成员变量访问:永远看引用类型,不存在“变量多态”这回事
接口多态的特殊处理
一个类可以实现多个接口,不同类中同一接口方法在各自虚方法表里的位置可能不同。因此 JVM 对接口方法调用使用 invokeinterface 指令——它不依赖固定偏移量,而是遍历目标类的接口方法表匹配签名,开销略高于 invokevirtual,但保证了多实现的正确性。


















