编译时多态在编译阶段绑定方法,依赖重载;运行时多态在运行阶段绑定方法,依赖继承、重写和向上转型;字段访问无多态,方法调用有多态。

编译时多态和运行时多态的核心区别在于:**方法调用的绑定时机不同——一个在编译阶段就确定了具体执行哪个方法,另一个要等到程序真正运行、对象类型明确后才决定。**
看绑定发生的时间点
编译时多态(静态多态):编译器在翻译代码时,仅凭方法名、参数个数、类型和顺序就能唯一确定调用哪个函数。比如重载的 add(int, int) 和 add(double, double),传 1, 2 就一定选前者,这个决策在生成字节码前就完成了。
运行时多态(动态多态):编译器只检查语法和接口是否合法,不决定最终执行谁的方法。比如 Animal a = new Dog(); a.speak();,编译时只知道 Animal 有 speak() 方法,但实际调用 Dog 还是 Cat 的版本,得等运行到这一行、看到 a 当前指向哪个真实对象才能定。
看实现方式和依赖条件
- 编译时多态靠的是“同名不同参”,典型是方法重载(overload)、运算符重载、函数模板。不需要继承关系,也不需要父类引用指向子类对象。
-
运行时多态靠的是“继承 + 重写 + 向上转型”。必须有父子类(或接口与实现类)关系;子类要重写父类的非 private、非 static 方法;变量声明为父类型,但 new 出来的是子类实例(如 List
list = new ArrayList(); )。
看调用行为的表现差异
同样是“调用一个名字”,结果可能完全不同:
- 重载方法:print("hello") 和 print(42) 是两个完全独立的方法,编译器选哪个,只看括号里写了什么值、是什么类型。
- 重写方法:a.run() 这一行代码,在整个程序中始终是同一行,但每次运行时,如果 a 指向 Car 就跑轮子,指向 Plane 就起飞——行为由对象的实际类型驱动,不是由代码行本身决定。
看属性访问和方法调用是否一致
这是容易混淆但很关键的一点:
- 方法调用走运行时类型 → 多态生效(调子类重写版)
- 字段(属性)访问走编译时类型 → 没有多态(只取声明类型的字段值)
例如:Base b = new Sub(); System.out.println(b.value); 输出的是 Base 类里的 value,哪怕 Sub 类也定义了同名字段且值不同——因为字段不参与动态绑定。










