java多态方法调用执行子类重写版本,前提是方法非static、非private、非final且被子类@override重写;编译期检查方法存在性并生成invokevirtual指令,运行时jvm根据对象实际类型查虚方法表动态绑定。

Java 中多态调用方法时,执行哪个版本由运行时对象的实际类型决定,而不是引用变量的声明类型。关键前提是该方法必须是可被重写的实例方法——即非 static、非 private、非 final,且在子类中确实被重写(@Override)。
看 new 的是谁,但前提是方法被重写了
语句如 Animal a = new Dog(); a.sound(); 最终执行的是 Dog.sound(),因为:
- 对象在堆中真实类型是
Dog,JVM 在运行时依据这个类型查找方法 - 如果
Dog类重写了sound(),就调用它的版本;如果没有重写,就沿继承链向上找,最终执行Animal.sound() - 所以“new 的是哪个类”只是必要条件,不是充分条件——没重写,就不会执行子类逻辑
编译期只检查语法,运行期才定具体方法
编译器只做两件事:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 确认
a.sound()在Animal类中存在(否则编译失败) - 生成
invokevirtual Animal.sound字节码指令,不硬编码跳转地址
真正的方法绑定发生在运行时:JVM 读取对象头中的类元数据指针,定位到 Dog 类的虚方法表(vtable),按方法签名查表,拿到 Dog.sound 的实际入口地址后跳转执行。
哪些方法不走这套流程?
以下情况不参与动态绑定,也就没有多态效果:
-
静态方法:调用看引用类型,
Animal a = new Dog(); a.staticMethod()执行的是Animal.staticMethod -
私有方法:隐式
final,编译期绑定,子类里同名方法只是新方法,不是重写 -
构造器和
final方法:不可重写,自然不触发动态分派 - 重载(overload)方法:选择发生在编译期,依据参数的静态类型,与运行时对象无关
快速验证你调用的到底是不是多态版本
遇到不确定时,可用这几个办法现场确认:
- 在被调用方法里加
System.out.println(this.getClass().getName());,输出的就是真实执行类 - 把方法改成
static,如果行为变了(比如输出变成父类名),说明原来走的是动态绑定 - 用
javap -v查字节码,看到invokevirtual指令,基本就是多态调用
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










