编译看左边,运行看右边:编译时依据引用类型检查方法合法性,运行时根据实际对象类型动态绑定重写方法,实现多态;字段和静态方法不遵循此规则。

这句话是 Java(或其他支持面向对象的编程语言)中对多态方法调用机制的一种经验性总结,核心说的是:编译时根据引用类型(左边)检查方法是否合法;运行时根据实际对象类型(右边)决定调用哪个具体实现——也就是动态绑定(虚方法调用)。
编译看左边:只认引用声明的类型
编译器在编译阶段不关心你 new 的到底是什么对象,只看变量声明的类型(即“左边”),以此判断:这个方法能不能被调用、参数是否匹配、返回值是否兼容。
例如:
Animal a = new Dog(); a.shout(); // ✅ 编译通过 —— 因为 Animal 类里有 shout() 方法<br> a.bark(); // ❌ 编译失败 —— Animal 类没有 bark(),哪怕 Dog 有也不行
即使 a 实际指向 Dog 对象,“左边”是 Animal,编译器就只允许调用 Animal 中定义或继承的方法。
运行看右边:真正执行哪个方法由对象实例决定
一旦编译通过,JVM 在运行时会查看 a 所指向的真实对象类型(即 new 出来的那个类,也就是“右边”),再根据该类中对方法的重写(override)情况,选择最终执行的版本。
比如:
class Animal { void shout() { System.out.println("animal sound"); } }<br>
class Dog extends Animal { void shout() { System.out.println("woof!"); } }<br>
class Cat extends Animal { void shout() { System.out.println("meow~"); } }<br>
<br>
Animal a1 = new Dog();<br>
Animal a2 = new Cat();<br>
a1.shout(); // 输出 "woof!"<br>
a2.shout(); // 输出 "meow~"
两个变量声明类型都是 Animal,但运行时分别调用 Dog 和 Cat 的 shout() 实现——这就是“运行看右边”。
为什么叫“虚方法绑定”?
“虚方法”指被子类可能重写、且需在运行时才能确定调用目标的方法(Java 中除 static、final、private 方法外,普通实例方法默认都是虚方法)。“绑定”是指把方法调用和具体实现关联起来的过程。
- 静态绑定(编译期):如 static、final、构造器、private 方法,编译时就确定了目标。
- 动态绑定(运行期):普通实例方法,编译只做合法性检查,真正绑定发生在运行时,由 JVM 的虚方法表(vtable)机制支持。
注意几个常见误区
- “左边”不是代码里写的类名位置,而是引用变量的声明类型。比如
Object obj = new ArrayList();,左边是 Object,不是 ArrayList。 - 属性(字段)不参与多态:访问的是声明类型的字段,不是实际对象的字段(即“编译运行都看左边”)。
- 静态方法看左边:无论右边是什么类型,static 方法调用永远由引用类型决定,不体现多态。
- 构造器不能被重写,所以也不涉及此规则。

















