java多态核心是“编译看左边,运行看右边”:编译器按声明类型检查方法合法性,jvm运行时通过对象实际类型查vtable调用重写方法;字段、static、private、final不参与多态。

Java 多态调用规则的核心就是“编译看左边,运行看右边”,它不是口诀,而是编译器和 JVM 各司其职的真实体现:编译器只管语法合法、类型可达;JVM 才决定最终执行谁的方法体。
成员方法:编译检查声明类型,运行调用实际类型
非 private、非 static、非 final 的实例方法支持重写,因此走动态分派:
- 编译时,只认变量声明的类型(左边),比如 Animal a = new Dog();,调用 a.shout() 必须在 Animal 类中存在且可访问,否则直接报错
- 运行时,JVM 查对象头中的 klass 指针,定位到 Dog.class,再查它的虚方法表(vtable),若 Dog 重写了 shout(),就跳转执行子类版本
- @Override 很关键——它让编译器强制校验方法签名是否真能覆盖父类方法,避免因参数或返回值不匹配导致“看似重写实为重载”的陷阱
成员变量:编译和运行都看左边
字段不参与多态,因为字段不会被放进虚方法表,访问在编译期就确定了内存偏移量:
- Animal a = new Dog(); 中,a.name 永远读取的是 Animal 类定义的 name 字段,哪怕 Dog 也声明了同名字段,那只是隐藏(shadowing),不是覆盖
- 如果想访问子类字段,必须显式转型:((Dog)a).name,但前提是编译器允许——即 Dog 类确实有该字段且可见
静态方法:编译和运行都看左边
静态方法属于类,不依赖实例,也不进 vtable,绑定发生在编译期:
- Animal a = new Dog(); a.eat(); 调用的是 Animal.eat(),哪怕 Dog 也定义了同名静态方法,也不会被触发
- 本质是 invokestatic 指令,目标类由引用变量的声明类型决定,与 new 出来的对象无关
- 子类中同名静态方法只是“隐藏”父类方法,不是重写,不能构成多态行为
哪些情况完全不走“运行看右边”?
以下四类成员不进虚方法表,全部静态绑定,编译期就定死:
- private 方法:无法被继承或重写,JVM 用 invokespecial 直接调用,连查表都不需要
- final 方法:禁止重写,同样走 invokespecial
- static 方法:如上所述,按声明类型绑定
- 字段:访问路径在编译时计算完成,不依赖运行时对象类型
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











