重写是子类覆盖父类方法,体现运行时多态;重载是同一类中同名不同参的方法,属编译时多态。二者发生位置、绑定时机、jvm处理机制截然不同,@override仅适用于重写。

重写(Override)是子类改父类方法,重载(Overload)是同一个类里多个同名但参数不同的方法
重写的本质是运行时多态:调用哪个版本,取决于对象实际类型;重载是编译时决定的,只看变量声明类型和传入参数的静态类型。很多人混淆,是因为都用了相同方法名,但发生位置、触发时机、JVM处理方式完全不同。
@Override 注解只对重写有效,加在重载方法上会编译报错
这是最直接的区分信号。Java 要求重写必须加 @Override(除非父类方法是 private 或 final),而重载方法加了它会提示 Method does not override method from its superclass。
- 重写:必须有继承关系,方法签名(名称 + 参数类型)完全一致,返回类型协变,访问权限不能更严格
- 重载:发生在同一个类中,参数列表不同(类型、个数、顺序任一不同),返回类型和访问修饰符可任意
- 构造方法只能重载,不能重写(没有继承构造方法这回事)
重载解析在编译期完成,重写绑定在运行期发生
这意味着重载选哪个方法,javac 就定死了;而重写调用谁,得等 new 出来的对象实际是哪个子类实例才能确定。这也是为什么 static 方法可以重载但不能真正重写——它不参与动态分派。
- 重载示例:
print(String)和print(Object)在同一类里,传"abc"会选前者;但传new Object()就选后者 - 重写示例:父类
Animal.speak()输出 "sound",子类Dog.speak()输出 "woof",用Animal a = new Dog(); a.speak();打印的是 "woof" - 如果把
speak()声明为static,那无论a实际是什么类型,都只会调父类版本
容易被忽略的坑:重载可能意外遮蔽重写,尤其涉及自动装箱和 varargs
比如父类有 void handle(int x),子类加了个 void handle(Integer x),看起来像重载,但其实破坏了重写契约——因为 Integer 参数不会触发对父类 int 版本的重写,反而让子类失去多态行为。
立即学习“Java免费学习笔记(深入)”;
- 基本类型和包装类混用重载,极易导致调用路径出人意料
- 带
...的重载方法优先级最低,但容易和其它重载产生歧义,编译器可能报reference to xxx is ambiguous - 泛型擦除后,
list(List<string>)</string>和list(List<integer>)</integer>无法构成重载(擦除后都是list(List)),会编译失败







