java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java方法重载与重写区别

Java中方法重载与重写的区别与避坑指南

作者:希望永不加班

在 Java 基础面试中,重载(Overload)和重写(Override)是必考知识点;在实际开发中,二者也是实现多态、代码复用、业务扩展的核心基础,本文给大家介绍了Java中方法重载与重写的区别与避坑指南,需要的朋友可以参考下

引言

在 Java 基础面试中,重载(Overload)重写(Override)必考知识点;在实际开发中,二者也是实现多态、代码复用、业务扩展的核心基础。

但绝大多数同学只懂皮毛,分不清底层差异,经常踩坑:把重载当成重写、静态方法误判重写、协变返回混淆、参数匹配出错、多态调用失效等问题层出不穷。

一、Java 两大多态机制

想要彻底理解重载和重写,首先要搞懂 Java 的两种多态,这是二者的本质区别:

1. 静态多态(编译期多态)

程序在编译阶段就已经确定调用哪个方法,方法绑定不可更改,重载属于静态多态。

2. 动态多态(运行期多态)

程序在运行阶段根据对象的真实类型,动态绑定对应方法,重写属于动态多态,也是 Java 面向对象的核心特性。

二、方法重载(Overload)完整详解

1. 官方定义

方法重载:在同一个类中,存在多个方法名完全相同,但参数列表不同的方法,这种现象就是方法重载。

2. 触发重载的三种条件(满足其一即可)

参数列表不同,只包含以下三种情况,除此之外,所有条件都不参与重载判定

3. 合法重载代码示例

public class OverloadDemo {
    // 基础方法
    public void test(int a) {
        System.out.println("参数为int类型");
    }
    // 重载1:参数个数不同
    public void test(int a, int b) {}
    // 重载2:参数类型不同
    public void test(String a) {}
    // 重载3:参数顺序不同(不同类型)
    public void test(int a, String b) {}
    public void test(String b, int a) {}
}

4. 重载判定的「四大无关项」

很多新手踩坑:返回值、访问权限、方法异常、方法修饰符,完全不参与重载判断!

仅靠这四项不同,无法构成重载,直接编译报错!

// 错误示例:仅返回值不同,不构成重载
public void demo(){}
public int demo(){ return 1; }
// 错误示例:仅权限不同,不构成重载
public void func(){}
private void func(){}

5. 重载底层原理

编译阶段,编译器会根据方法名+参数列表生成唯一的方法签名,区分不同重载方法。

简单说:代码写完,编译完成,调用哪个方法就已经定死了,不存在运行时变化,这就是静态绑定。

三、方法重写(Override)详解

1. 官方定义

方法重写:发生在父子类继承关系中,子类对父类中非私有、非静态、非final的实例方法进行重新实现,保持方法签名一致,覆盖父类原有逻辑,实现子类个性化业务。

2. 重写五大硬性规则

1. 方法名、参数列表必须和父类完全一致

2. 权限修饰符:子类权限 ≥ 父类权限(只能放大,不能缩小)

3. 返回值:支持协变返回(引用类型可返回子类,基本类型必须一致)

4. 异常:子类抛出的受检异常,不能比父类更宽泛

  1. 5. 禁止重写的方法:private、static、final、构造方法

3. 合法重写代码示例

class Person {}
class Student extends Person {}
class Father {
    public Person getInfo() {
        return new Person();
    }
    public void say() throws Exception {}
}
class Son extends Father {
    // 合法:协变返回,返回子类类型
    @Override
    public Student getInfo() {
        return new Student();
    }
    // 合法:子类异常范围更小
    @Override
    public void say() throws RuntimeException {}
}

4. 重写底层原理

重写基于动态绑定:编译时看父类引用,运行时看真实对象类型。

JVM 在运行时通过**虚方法表(vtable)**找到子类重写后的方法执行,这也是多态的核心实现。

四、重载 & 重写 终极对比表

对比维度

重载 Overload

重写 Override

发生范围

同一个类内部

父子类继承关系中

方法名

必须相同

必须相同

参数列表

必须不同必须完全一致

返回值

无要求,不参与判定

基本类型一致,引用类型支持协变

权限修饰符

无要求

权限只能扩大,不能缩小

异常抛出

无要求

受检异常范围只能更小或相同

绑定时机

编译期静态绑定

运行期动态绑定

多态类型

静态多态

动态多态

注解支持

无专属注解

必须加 @Override 校验

五、注意事项

1:静态方法「看似重写,实则覆盖」

核心结论:静态方法不能重写,只能覆盖,多态完全失效!

class Father {
    public static void show() {
        System.out.println("父类静态方法");
    }
}
class Son extends Father {
    public static void show() {
        System.out.println("子类静态方法");
    }
}
// 测试调用
public class Test {
    public static void main(String[] args) {
        Father f = new Son();
        f.show(); // 输出:父类静态方法
    }
}

原因:静态方法属于类,不属于对象,编译期绑定父类类型,和子类无关,不存在多态。

2:参数类型不一致,误把「重载」当「重写」

这是新手最高频错误!参数细微不同,根本不是重写,是重载!

class Father {
    public void test(Object obj) {}
}
class Son extends Father {
    // 不是重写!是重载!参数类型不一致
    public void test(String str) {}
}

避坑方案:重写必须加 @Override,编译器自动校验,杜绝此类问题。

3:private 方法不存在重写

父类私有方法对子类不可见,子类同名方法是全新方法,和重写无关。

class Father {
    private void test() {
        System.out.println("父类私有方法");
    }
}
class Son extends Father {
    public void test() {
        System.out.println("子类方法");
    }
}

4:权限修饰符越改越小,编译报错

重写规则:子类访问权限不能比父类严格

权限等级:public > protected > 默认包访问权限 > private

5:受检异常范围扩大,重写失败

运行时异常无限制,受检异常必须子类 ≤ 父类,不能抛出更大范围异常。

6:可变参数与数组参数冲突,无法重载

可变参数本质是数组,二者视为同一个方法,不构成重载:

// 编译报错,冲突
public void fun(int[] arr){}
public void fun(int... arr){}

7:仅参数名称不同,不构成重载

重载只看参数类型、个数、顺序,参数名不参与判定

六、@Override 注解的核心价值

很多人以为它是摆设,其实是防坑神器

1. 强制编译器校验当前方法是否为合法重写

2. 杜绝参数写错、返回值错误、静态覆盖、权限错误等所有重写问题

3. 提升代码可读性,一眼区分普通方法和重写方法

开发规范:所有重写方法,必须添加 @Override 注解!

七、总结

重载:同类、同名不同参、编译绑定、静态多态,为了灵活适配多场景调用。

重写:父子、同名同参、运行绑定、动态多态,为了子类个性化扩展。

记住:重载看参数,重写看继承;重载编译定,重写运行变。

写在最后

重载和重写看似简单,却是 Java 面向对象、多态机制的基石,也是面试和实际开发的高频考点。很多高级特性(多态调用、框架底层封装、方法扩展)都建立在这两个特性之上。

看似基础的知识点,往往最容易藏坑。基础打牢,才能走得更远,吃透这篇,彻底告别重载重写相关bug和面试短板!

以上就是Java中方法重载与重写的区别与避坑指南的详细内容,更多关于Java方法重载与重写区别的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文