场景痛点​:
面试中被问到"重载和重写有什么区别?"时,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 { ... }
}

四、终极总结:一句话道破本质

特性 一句核心总结
重载 同一类中的方法扩展
"同名不同参,编译定乾坤"
重写 父子类间的行为覆盖
"同参同返回,运行见真身"

📌 ​黄金记忆点​:
重载看参数​ → 改变参数列表就是新方法
重写看类型​ → 覆盖必须保持契约一致(里氏替换原则)


附:真题自测(答案见评论区)

  1. 以下代码输出什么?

    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();
        }
    }
  2. 能否重写 private 方法?

  3. 重载方法是否可以改变返回类型?


我是CSDN博主青川入门,关注我获取更多Java硬核知识!​
🔥 下期预告:《抽象类 vs 接口:你从未搞清楚的7大差异》

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐