重载是编译期静态绑定,依据参数类型、数量、顺序选择方法;重写是运行期动态绑定,依据对象实际类型选择实现;字段访问不参与重写,始终静态绑定。

关键不在名字像不像,而在“谁在什么时候、依据什么做决定”——重载由编译器在写完代码时就定死了调用哪个方法;重写则要等程序跑起来,看到对象真实长什么样,才决定执行哪段逻辑。
重载是编译期静态绑定:看参数,不看对象
编译器只关心你传了什么类型的实参、几个参数、顺序如何。它在编译阶段就从当前类里所有同名方法中挑出唯一匹配的一个,生成固定调用指令。
- 哪怕父类引用指向子类对象,比如 Animal a = new Dog();,调用 a.print(42) 仍按 Animal 类型查重载方法,选的是 print(int) 版本,不是看右边是不是 Dog
- 返回值类型、访问修饰符、异常声明,都不参与重载判断
- 仅靠返回值不同(如 int func() 和 String func())不能构成重载,编译报错
重写是运行期动态绑定:看对象,不看引用
JVM 或运行时环境不认你声明的类型,只认堆里那个对象实际属于哪个类。它通过虚方法表(vtable)在运行时跳转到真正该执行的方法体。
- 还是 Animal a = new Dog();,调用 a.speak() 时,JVM 发现 a 实际是 Dog 实例,于是执行 Dog::speak()
- 重写要求方法签名(名 + 参数列表)严格一致,返回值可协变(如父类返回 Object,子类可返回 String)
- private、static、final 方法不能被重写,因为它们不参与动态分派
绑定时机不同,导致行为表现完全不同
同一个调用语句,在重载和重写场景下,结果可能截然相反:
- 重载方法调用:取决于变量声明类型和实参字面量类型,编译完就不可更改
- 重写方法调用:取决于new 出来的实际对象类型,哪怕多次赋值改变引用指向,运行时仍能正确响应
- 字段访问永远不重写——哪怕子类定义了同名字段,访问的仍是引用类型声明的字段,这是静态绑定的铁律
一句话记住核心差异
重载是“我传什么,你就给我哪个版本”,编译期拍板;重写是“你到底是谁,我就给你配哪个实现”,运行期确认。两者共存时,先按重载选签名,再按重写选实现——两道关卡,缺一不可。











