重载发生在编译期,看方法签名(参数类型、个数、顺序),与返回值、修饰符无关;重写发生在运行期,看对象实际类型,要求非private/static/final实例方法,且需满足权限不缩、异常不扩、协变返回等约束。

重载(Overload)和重写(Override)是 Java 基础中高频面试题,答出区别只是及格线,答出“为什么这样设计”“哪些细节容易踩坑”才算完美。
重载:发生在编译期,看的是方法签名
重载指在同一个类中,方法名相同但参数列表不同(类型、个数、顺序任一不同),返回值类型、访问修饰符、异常声明不影响重载判断。编译器根据调用时的实参类型和个数,在编译阶段就确定调用哪个方法。
- 构造方法也可以重载(这是新手常忽略的点)
- 重载跟泛型擦除有关:比如
void test(List<String>)和void test(List<Integer>)不能构成重载(擦除后都是List) - 基本类型自动提升(如
int→long)可能引发意料外的重载匹配,建议显式转型或避免歧义设计
重写:发生在运行期,看的是对象实际类型
重写指子类对父类非 private、非 static、非 final的实例方法进行重新实现。JVM 在运行时根据对象的实际类型(而非引用类型)决定调用哪个版本,这就是动态绑定的核心体现。
- @Override 注解不是必须的,但强烈建议加上——它能帮你在父类方法被删除或改名时提前报错
- 子类重写方法的访问权限不能比父类更严格(public → protected ✅,protected → private ❌)
- 抛出的异常类型不能比父类更宽(只能是父类异常的子类,或不抛异常)
- 静态方法可以“同名同参”,但这不是重写,而是隐藏(hiding),调用取决于引用类型,不是运行时多态
一个经典对比例子,瞬间讲清本质
假设:
立即学习“Java免费学习笔记(深入)”;
class Animal { void sound() { System.out.println("animal"); } }
class Dog extends Animal { void sound() { System.out.println("wang"); } }
执行:
Animal a = new Dog(); a.sound(); // 输出 "wang" → 这是重写,运行时决定
再加一个重载:
class Dog extends Animal {
void sound() { System.out.println("wang"); }
void sound(String s) { System.out.println("wang " + s); }
}
执行:
Dog d = new Dog();
d.sound(); // 调用无参 version
d.sound("!"); // 调用有参 version → 编译期就绑定了
面试加分项:说清设计意图和常见误区
重载是为了提供更自然、更灵活的 API 使用方式(比如 print(String)、print(int)、print(Object));重写则是为了实现多态,让子类能定制行为逻辑,是面向对象“开闭原则”的基础支撑。
- 误区1:“重写可以改变返回类型”——只有协变返回类型允许(子类方法返回父类方法返回类型的子类),且仅限引用类型
- 误区2:“private 方法能被重写”——不能,它对子类不可见,子类里同名方法只是新定义
- 误区3:“重载和重写可以同时发生”——可以,但它们作用域和机制完全独立,不要混为一谈
不复杂但容易忽略。把签名、时期、权限、异常、多态这几个锚点讲清楚,再带一个自己写的例子,面试官基本就点头了。


















