Java多态核心是运行期动态绑定,依赖invokevirtual指令与虚方法表(vtable)实现:父类引用指向子类对象时,JVM根据实际类型查子类vtable调用重写方法;静态方法、private方法和成员变量不参与多态。

Java中多态的核心原理是编译期绑定(静态绑定)与运行期绑定(动态绑定)的结合,关键在于方法调用的实际执行目标由运行时对象的真实类型决定,而非引用变量的声明类型。
多态发生的三个必要条件
只有同时满足以下三点,Java中才会体现多态行为:
- 继承关系(或实现接口):子类继承父类,或类实现接口
- 方法重写(Override):子类重写了父类(或接口)中的非静态、非private、非final方法
- 父类(或接口)引用指向子类对象:如 Animal a = new Dog();
字节码层面:invokevirtual指令的作用
编译后的字节码中,对重写方法的调用统一使用 invokevirtual 指令。它不直接跳转到某个具体方法,而是根据栈顶对象的实际类型,在该类型的虚方法表(vtable)中查找对应方法入口。
每个类在加载时,JVM会为其构建一张虚方法表,表中按声明顺序存放所有可被重写的方法地址。子类的vtable会继承并覆盖父类中被重写的方法条目。运行时,JVM查子类vtable,自然调用到子类版本——这就是动态分派的底层机制。
立即学习“Java免费学习笔记(深入)”;
静态方法、属性和private方法不参与多态
因为它们不走 invokevirtual 流程:
- 静态方法绑定发生在编译期(invokestatic),只看引用类型,如 A.staticMethod() 不会因 A a = new B(); 而调用B中的同名静态方法
- 成员变量访问也按引用类型解析(即“变量不重写”),a.field 取的是A类定义的field,哪怕B中定义了同名字段
- private方法无法被重写,编译器直接确定调用目标(invokespecial),也不进入vtable查找流程
接口多态与默认方法的特殊性
接口引用多态同样依赖 invokevirtual,但JVM使用的是接口方法表(itable)。Java 8+ 的默认方法若被子类重写,则调用子类实现;若未重写,且实现类只有一个接口提供该默认方法,就直接调用接口中的默认实现。多个接口含同签名默认方法时,编译报错,强制要求实现类显式覆盖——这是为避免动态分派歧义而做的编译期约束。
基本上就这些。多态不是语法糖,而是JVM运行时通过类型信息+方法表+指令协作完成的动态决策过程。











