面试必问:彻底吃透 Java 重载(Overload)与重写(Override)的本质区别!
·
场景痛点:
面试中被问到"重载和重写有什么区别?"时,90%的求职者只能说出"参数不同"和"覆盖父类"这类表面答案,却讲不清底层原理和设计思想。本文用真实代码解剖二者本质差异,帮你真正吃透多态核心思想!
一、最速区分表(保存收藏!)
| 维度 | 重载 (Overload) | 重写 (Override) |
|---|---|---|
| 类关系 | 同一个类中 | 父子类之间 |
| 方法名 | 必须相同 | 必须相同 |
| 参数列表 | 必须不同(类型/数量/顺序) | 必须相同 |
| 返回类型 | 可不同(需兼容) | 子类可缩小或相同(JDK5+) |
| 异常抛出 | 可不同 | 子类异常 ≤ 父类异常(不能更宽) |
| 访问权限 | 可不同 | 子类权限 ≥ 父类权限(不能更严) |
| 绑定机制 | 编译时静态绑定 | 运行时动态绑定 |
| 设计目的 | 增强方法灵活性 | 实现多态特性 |
二、核心差异深度解剖
🎯 1. 参数列表的"变与不变"
重载:参数必须不同 → 本质是新方法
class Calculator {
// 重载示例:参数数量不同
int add(int a, int b) { return a + b; }
int add(int a, int b, int c) { return a + b + c; } // ✅
// 重载示例:参数类型不同
double add(double a, double b) { return a + b; } // ✅
}
重写:参数必须相同 → 否则视为隐藏父类方法
class Animal {
void eat(String food) { /* ... */ }
}
class Dog extends Animal {
// ❌ 错误重写:参数不同(实际是新方法,隐藏父类eat)
void eat(int amount) { ... }
// ✅ 正确重写
@Override
void eat(String food) { /* 覆盖实现 */ }
}
⚡ 2. 动态绑定 vs 静态绑定
重载的静态绑定:编译时按引用类型决定调哪个方法
class Printer {
void print(String s) { System.out.println("String: " + s); }
void print(Integer i) { System.out.println("Integer: " + i); }
}
public static void main(String[] args) {
Printer p = new Printer();
Object obj = "Hello";
p.print(obj); // 编译错误!找不到合适方法
// obj类型为Object,但Printer无print(Object)方法
}
重写的动态绑定:运行时按对象实际类型决定方法
class Shape {
void draw() { System.out.println("Drawing Shape"); }
}
class Circle extends Shape {
@Override
void draw() { System.out.println("Drawing Circle"); }
}
public static void main(String[] args) {
Shape s = new Circle(); // 父类引用指向子类对象
s.draw(); // 输出"Drawing Circle"(运行时按Circle类型执行)
}
三、面试直击:7大高频考点解析
💥 考点1:能否重写静态方法?
class Parent {
static void show() { System.out.println("Parent"); }
}
class Child extends Parent {
static void show() { System.out.println("Child"); } // ❌ 不是重写!
// 只是隐藏父类方法
}
重点:静态方法无多态性!通过父类引用调用时,始终执行父类方法
💥 考点2:返回值类型兼容规则
class Base {
Number get() { return 1; } // 返回Number类型
}
class Derived extends Base {
@Override
Integer get() { return 2; } // ✅ 返回值范围缩小(JDK5+协变返回)
// ❌ 非法重写:Object比Number范围大
// Object get() { ... }
}
💥 考点3:访问权限的"里氏替换原则"
class Vehicle {
protected void start() { ... } // protected权限
}
class Car extends Vehicle {
@Override
public void start() { ... } // ✅ 权限扩大
// ❌ 非法重写:private < protected
// @Override
// private void start() { ... }
}
💥 考点4:异常处理的限制
class Database {
void connect() throws SQLException { ... }
}
class MySQL extends Database {
@Override
void connect() { ... } // ✅ 不抛异常(缩小范围)
// ❌ 非法重写:IOException是新异常
// void connect() throws IOException { ... }
// ✅ 正确:可抛出更具体的SQLTimeoutException(属于SQLException子类)
// void connect() throws SQLTimeoutException { ... }
}
四、终极总结:一句话道破本质
| 特性 | 一句核心总结 |
|---|---|
| 重载 | 同一类中的方法扩展 "同名不同参,编译定乾坤" |
| 重写 | 父子类间的行为覆盖 "同参同返回,运行见真身" |
📌 黄金记忆点:
重载看参数 → 改变参数列表就是新方法
重写看类型 → 覆盖必须保持契约一致(里氏替换原则)
附:真题自测(答案见评论区)
-
以下代码输出什么?
class A { void m() { System.out.println("A"); } } class B extends A { void m() { System.out.println("B"); } } public class Test { public static void main(String[] args) { A a = new B(); a.m(); } } -
能否重写 private 方法?
-
重载方法是否可以改变返回类型?
我是CSDN博主青川入门,关注我获取更多Java硬核知识!
🔥 下期预告:《抽象类 vs 接口:你从未搞清楚的7大差异》
更多推荐
所有评论(0)