Java多态需继承(或接口实现)、方法重写、父类引用指向子类对象三者缺一不可,由JVM通过虚方法表和invokevirtual指令在运行时动态绑定。

Java 中多态靠继承(或接口实现)、方法重写、父类引用指向子类对象三者协同实现,底层由 JVM 通过虚方法表和 invokevirtual 指令完成运行时动态绑定。关键不在“写法多”,而在三个条件缺一不可,且绑定时机决定行为归属。
方法重写是多态的逻辑前提
重写不是简单地“名字一样”,而是有明确契约:
- 子类方法名、参数列表(个数、类型、顺序)必须与父类完全一致
- 返回类型可相同,或为父类返回类型的子类型(协变返回)
- 访问修饰符不能比父类更严格(如父类是
protected,子类不能是private) -
static、final、private方法无法重写——它们不参与多态 - 重写必须发生在父子类之间;同名但无继承关系的方法,只是独立方法,不是重写
向上转型是多态的表达形式
用父类类型声明变量,实际指向子类对象,这是多态发生的“载体”:
-
Animal a = new Dog();—— 编译期认为a是Animal类型,只允许调用Animal中定义的方法 - 运行期
a实际是Dog实例,因此a.makeSound()执行的是Dog.makeSound() - 子类独有方法(如
Dog.fetch())无法通过a直接调用,需向下转型才能访问
动态绑定是多态的底层执行机制
JVM 不在编译时决定调哪个方法,而是在运行时根据对象真实类型查表跳转:
立即学习“Java免费学习笔记(深入)”;
- 每个类加载后,JVM 在方法区为其生成一张虚方法表(vtable),按固定顺序存放所有可被重写的方法地址
- 调用
a.makeSound()时,字节码中是invokevirtual指令:先获取a的实际类型(Dog),再查Dog的 vtable 中makeSound对应的索引位置,跳转到该地址执行 - 哪怕多个子类重写同一方法,只要签名一致,它们在各自 vtable 中的索引就相同,保证查找高效
- 接口方法使用
invokeinterface,因实现类可能实现多个接口,需按签名匹配而非固定索引
哪些情况不走动态绑定?
不是所有方法调用都支持多态,以下情形属于静态绑定(编译期确定):
-
static方法:只看引用类型,Animal a = new Dog(); a.staticMethod()调用的是Animal.staticMethod -
private/final/ 构造方法:无法重写,自然无动态分派 - 成员变量访问:永远按引用类型解析,
a.name取的是Animal类中的name字段,不存在“变量多态”


















