--- title: "04-重写与重载" created: 2025-11-25 tags: - Java --- # 重写与重载 ## 核心概念 重写(Override)和重载(Overload)是Java中多态性的两种重要表现形式: - **重写(Override)**:运行时多态,发生在继承关系中 - **重载(Overload)**:编译时多态,发生在同一个类中 理解它们的机制和区别,是掌握Java面向对象编程的关键。 --- ## 一、方法重写(Override) ### 1.1 基本语法 ```java class Parent { public void method(int x) { System.out.println("Parent method"); } } class Child extends Parent { // 重写父类方法 @Override public void method(int x) { System.out.println("Child method"); } } // 使用 Parent p = new Child(); p.method(10); // 输出:Child method(运行时多态) ``` ### 1.2 重写的规则(两同两小一大) | 规则 | 说明 | 示例 | | --- | --- | --- | | **方法名相同** | 必须完全一致 | `method()` | | **参数列表相同** | 参数类型和顺序 | `method(int x, String y)` | | **返回类型相同或更小**(协变返回) | 可以是原返回类型的子类 | `Object → String` | | **异常相同或更小** | 不能抛出更大的异常 | `IOException → FileNotFoundException` | | **访问权限相同或更大** | 不能降低可见性 | `protected → public` | ### 1.3 @Override注解 ```java class Parent { public void method() {} } class Child extends Parent { // ✅ 正确:使用@Override检查重写 @Override public void method() {} // ❌ 错误:方法名写错,编译器会报错 @Override public void methd() {} // 编译错误 } ``` ### 1.4 协变返回类型 ```java class Animal { public Animal getInstance() { return new Animal(); } } class Dog extends Animal { // 协变返回:返回类型可以是原返回类型的子类 @Override public Dog getInstance() { return new Dog(); } } ``` ### 1.5 异常处理 ```java class Parent { public void method() throws IOException { // 抛出较大的异常 } } class Child extends Parent { // ✅ 正确:抛出更小的异常 @Override public void method() throws FileNotFoundException { // 抛出更具体的异常 } // ❌ 错误:不能抛出更大的异常 // @Override // public void method() throws Exception { } // 编译错误 } ``` --- ## 二、方法重载(Overload) ### 2.1 基本语法 ```java class Calculator { // 重载:方法名相同,参数不同 public int add(int a, int b) { return a + b; } public double add(double a, double b) { return a + b; } public int add(int a, int b, int c) { return a + b + c; } } // 使用 Calculator calc = new Calculator(); calc.add(1, 2); // 调用 int add(int, int) calc.add(1.0, 2.0); // 调用 double add(double, double) calc.add(1, 2, 3); // 调用 int add(int, int, int) ``` ### 2.2 重载的规则 | 规则 | 说明 | 示例 | | --- | --- | --- | | **方法名相同** | 必须完全一致 | `add()` | | **参数列表不同** | 参数类型、数量、顺序 | `add(int,int)` vs `add(double,double)` | | **返回类型无关** | 仅靠返回类型区分无效 | `int add()` vs `double add()` 是错误的 | ### 2.3 重载的类型匹配 ```java class OverloadDemo { public void method(int x) { System.out.println("int"); } public void method(double x) { System.out.println("double"); } public void method(Integer x) { System.out.println("Integer"); } } // 调用顺序 OverloadDemo demo = new OverloadDemo(); demo.method(10); // 输出:int(精确匹配) demo.method(10.0); // 输出:double demo.method(Integer.valueOf(10)); // 输出:Integer ``` ### 2.4 可变参数重载 ```java class VarargsDemo { public void method(String... args) { System.out.println("String..."); } public void method(int... args) { System.out.println("int..."); } } VarargsDemo demo = new VarargsDemo(); demo.method("a", "b"); // 输出:String... demo.method(1, 2, 3); // 输出:int... ``` --- ## 三、重写 vs 重载 ### 3.1 核心区别 | 特性 | 重写(Override) | 重载(Overload) | | --- | --- | --- | | **发生位置** | 继承关系中的子类 | 同一个类中 | | **方法名** | 相同 | 相同 | | **参数列表** | 相同 | 不同 | | **返回类型** | 相同或协变 | 无关 | | **多态类型** | 运行时多态 | 编译时多态 | | **访问权限** | 不能降低 | 无限制 | ### 3.2 多态性对比 ```java class Parent { public void method(int x) { System.out.println("Parent"); } } class Child extends Parent { // 重写:运行时多态 @Override public void method(int x) { System.out.println("Child"); } // 重载:编译时多态 public void method(String s) { System.out.println("Child-String"); } } Parent p = new Child(); p.method(10); // 输出:Child(重写,运行时) p.method("hello"); // 编译错误(重载需要具体类型) ``` ### 3.3 方法调用的绑定 ```java class Parent { public static void staticMethod() { System.out.println("Parent static"); } public void instanceMethod() { System.out.println("Parent instance"); } } class Child extends Parent { public static void staticMethod() { System.out.println("Child static"); } @Override public void instanceMethod() { System.out.println("Child instance"); } } Parent p = new Child(); p.staticMethod(); // 输出:Parent static(静态绑定) p.instanceMethod(); // 输出:Child instance(动态绑定) ``` **绑定类型:** - **静态绑定**(编译时):static、private、final方法 - **动态绑定**(运行时):普通实例方法 --- ## 四、高频面试题 ### Q1: 重写和重载有什么区别? **答:** - **重写**:继承关系中子类覆盖父类方法,运行时多态 - **重载**:同一个类中方法名相同但参数不同,编译时多态 - 重写关注继承,重载关注同一类中的多个方法 ### Q2: 为什么static方法不能被重写? **答:** - static方法属于类,不属于对象实例 - 静态方法在编译时绑定,不支持运行时多态 - 子类中定义同名static方法是隐藏,不是重写 ### Q3: 协变返回类型是什么? **答:** - 子类重写方法可以返回父类方法返回类型的子类 - 增加了方法返回值的灵活性 - JDK 5引入的特性 ### Q4: 重载方法是如何匹配的? **答:** - 精确匹配优先 - 基本类型自动提升(int → long → float → double) - 装箱/拆箱 - 可变参数最后匹配 ### Q5: @Override注解的作用? **答:** - 编译器检查是否真的重写了父类方法 - 防止方法名拼写错误 - 提高代码可读性 --- ## 五、最佳实践 ### ✅ 推荐做法 ```java // 1. 使用@Override注解 @Override public void method() { } // 2. 重载方法保持语义一致 public void process(int value) { } public void process(String value) { } // 3. 谨慎使用可变参数重载 public void method(String... args) { } public void method(int... args) { } // 4. 协变返回类型 @Override public SubClass getInstance() { return new SubClass(); } ``` ### ❌ 避免做法 ```java // 1. 不要重载具有歧义的方法 public void method(int x) { } public void method(Integer x) { } // 容易混淆 // 2. 避免过度依赖重载 public void process(Object obj) { } public void process(String str) { } // 可能导致意外调用 // 3. 不要滥用static方法重写 public static void method() { } // 不是真正的重写 ``` --- ## 相关链接 - [[01-继承与多态|01-继承与多态]] - [[02-抽象类与接口|02-抽象类与接口]] - [[07-面向对象设计的SOLID原则|面向对象设计的SOLID原则]] --- ## 记忆口诀 ``` 重写子类覆盖,运行时多态显 参数类型不变,返回可协变 重载同名方法,参数来区分 静态方法不变,编译时绑定深 @Override护航法,检查重写无烦恼 ``` ## 相关笔记 本篇讲清了"怎么重写/怎么重载";[[04-方法重载和方法重写|方法重载和方法重写]] 与 [[05-编译时多态和运行时多态|编译时多态和运行时多态]] 则从"多态"角度再切一刀——重载绑定发生在编译期、重写绑定发生在运行期,这正是运行时多态的实现机制。三篇对照读,"两个绑定时机"这个面试高频点就闭环了。 --- ⬅️ [[03-访问权限|访问权限]] 🏠 [[00-Java|00-Java]] ➡️ [[05-面向对象or面向过程|面向对象or面向过程]]