Java方法重写Override:规则+底层本质+与重载区别

🏠个人主页:黎雁

🎬作者简介:C/C++/JAVA后端开发学习者

❄️个人专栏:C语言数据结构(C语言)EasyXJAVA游戏规划程序人生

✨ 从来绝巘须孤往,万里同尘即玉京

文章目录

Java方法重写Override:规则+底层本质+与重载区别

知识回顾

上一篇我们掌握了继承中成员变量的访问逻辑,通过"就近原则"解决了变量查找优先级问题,还学会用thissuper精准访问子类、父类变量,理清了同名变量的"隐藏"特性。这篇我们聚焦继承中方法的核心特性------方法重写(Override),它是实现多态的基础,也是高频考点。我们会从定义、规则、底层本质入手,结合实战案例区分"重写"与"重载",帮你彻底吃透方法重写的核心逻辑🚀!

📝 文章摘要

  • 核心摘要:本文讲解方法重写的定义、核心作用,拆解重写的6大语法规则,深入剖析虚方法表覆盖的底层原理,通过实战案例验证规则,同时对比方法重写与方法重载的核心区别,帮你精准掌握重写的用法,规避常见错误。
  • 阅读时长:10分钟
  • 适合人群&阅读重点
    🎯 Java初学者:重点牢记重写的语法规则,能正确实现子类对父类方法的重写,区分重写与重载。
    📚 高校计算机专业学生:从虚方法表角度理解重写的底层本质,掌握面向对象多态的实现原理。
    💻 初级开发工程师:规范重写方法的编写,解决重写引发的方法调用异常,提升代码的扩展性。
    📖 面试备考者:熟记重写规则、底层原理及与重载的区别,应对"重写vs重载""重写规则"类面试题。

一、方法重写是什么?定义与核心作用 📖

1.1 方法重写的官方定义

方法重写(Override) 是指在继承体系中,子类定义了一个与父类方法名、参数列表、返回值类型完全一致的非私有成员方法,子类方法会覆盖父类方法,当调用该方法时,优先执行子类的重写方法,而非父类原方法。

简单来说:重写是子类对父类方法的"重新实现",保留方法签名(方法名+参数列表),修改方法体逻辑,适配子类的个性化需求。

1.2 核心作用:实现"多态"与"个性化扩展"

重写的核心价值的是统一接口、个性化实现,让不同子类对同一方法有不同的执行逻辑,这是Java多态特性的基础。

实战案例:动物类体系的方法重写

父类Animal定义通用方法eat(),子类CatDog重写该方法,实现各自的吃饭逻辑:

java 复制代码
// 父类:Animal
public class Animal {
    // 父类方法:通用吃饭逻辑
    public void eat() {
        System.out.println("动物在吃饭");
    }
}

// 子类:Cat,重写eat()方法
public class Cat extends Animal {
    // 方法签名与父类完全一致,重写方法
    @Override
    public void eat() {
        System.out.println("加菲猫在吃猫粮");
    }
}

// 子类:Dog,重写eat()方法
public class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("哈士奇在吃狗粮");
    }
}

// 测试类
public class TestOverride {
    public static void main(String[] args) {
        Animal cat = new Cat();
        Animal dog = new Dog();
        cat.eat(); // 执行子类Cat的重写方法
        dog.eat(); // 执行子类Dog的重写方法
    }
}
运行结果
复制代码
加菲猫在吃猫粮
哈士奇在吃狗粮
核心亮点 ✨
  1. 统一接口:所有子类都遵循eat()方法签名,调用方式一致;
  2. 个性化实现:不同子类的eat()逻辑不同,适配自身特性;
  3. 注解增强:@Override注解是重写的规范标识,可强制校验重写规则(不符合则编译报错),推荐必加。

二、方法重写的6大核心规则(必记)✅

方法重写有严格的语法限制,违反任意一条都会编译报错,这是高频考点,必须逐条牢记:

规则1:方法签名完全一致

子类重写方法的方法名、参数列表 必须与父类方法完全一致(参数个数、类型、顺序都不能变),否则不构成重写(可能是重载)。

❌ 错误示例:参数列表不同,不构成重写

java 复制代码
// 父类方法
public void eat(String food) {}
// 子类方法:参数类型不同,非重写
public void eat(int num) {}

规则2:返回值类型需兼容

返回值类型需满足以下条件之一,否则报错:

  1. 与父类方法返回值类型完全一致(最常用);
  2. 子类返回值类型是父类返回值类型的子类 (协变返回值,JDK1.5+支持)。
    ✅ 正确示例(协变返回值)
java 复制代码
// 父类方法:返回Animal
public Animal getAnimal() { return new Animal(); }
// 子类方法:返回Cat(Animal的子类)
@Override
public Cat getAnimal() { return new Cat(); }

规则3:访问权限不能缩小

子类重写方法的访问权限,不能低于 父类方法的访问权限(保证子类方法可被正常调用),权限优先级:public > protected > 默认 > private

❌ 错误示例:父类public,子类protected(权限缩小)

java 复制代码
// 父类方法:public权限
public void eat() {}
// 子类方法:权限缩小,编译报错
@Override
protected void eat() {}

✅ 正确示例:父类protected,子类public(权限扩大/不变)

java 复制代码
// 父类方法:protected权限
protected void eat() {}
// 子类方法:权限扩大,合法
@Override
public void eat() {}

规则4:不能重写私有方法

父类的private修饰方法,子类无法继承,因此不能重写(子类若定义同名方法,仅为子类新方法,非重写)。

❌ 错误示例:重写父类私有方法

java 复制代码
// 父类私有方法
private void eat() {}
// 子类方法:非重写,仅为子类新方法
@Override // 报错:The method eat() of type Cat must override or implement a supertype method
public void eat() {}

规则5:不能重写静态方法

父类的静态方法属于类级别,子类无法重写(子类若定义同名静态方法,仅为子类静态方法,隐藏父类方法,非重写)。

❌ 错误示例:重写静态方法

java 复制代码
// 父类静态方法
public static void show() {}
// 子类方法:非重写,隐藏父类静态方法
@Override // 报错
public static void show() {}

规则6:异常声明不能扩大

子类重写方法声明的异常,不能比父类方法声明的异常范围更广 (可缩小或相同,也可不声明异常)。

❌ 错误示例:异常范围扩大

java 复制代码
// 父类方法:声明IOException
public void read() throws IOException {}
// 子类方法:声明Exception(范围更广),报错
@Override
public void read() throws Exception {}

重写规则总结表

规则维度 核心要求 错误后果
方法签名 方法名、参数列表完全一致 不构成重写,可能是重载
返回值类型 一致或子类协变返回值 编译报错
访问权限 不低于父类方法权限 编译报错
方法类型 仅非私有、非静态方法可重写 注解校验报错,不构成重写
异常声明 范围不大于父类方法异常 编译报错

三、底层本质:虚方法表的覆盖机制 🧠

方法重写的底层依赖JVM的虚方法表(Virtual Method Table),这是理解重写与多态的核心,也是面试高频考点。

3.1 重写前:父类与子类的虚方法表

  • 父类Animal加载时,生成虚方法表,存储eat()方法的地址(指向父类eat()实现);
  • 子类Cat加载时,先复制父类虚方法表的所有方法地址,再将自身eat()方法地址添加到表中(未重写时,地址与父类一致)。

3.2 重写后:虚方法表的覆盖

当子类Cat重写eat()方法后,会覆盖 虚方法表中对应的父类eat()方法地址,将其指向子类eat()的实现。

3.3 方法调用时的底层流程

当执行new Cat().eat()时,JVM的执行步骤:

  1. 找到Cat对象的引用,获取其对应的虚方法表;
  2. 在虚方法表中查找eat()方法的地址;
  3. 执行该地址指向的方法(子类重写后的eat())。

💡 核心结论:方法重写的本质是子类虚方法表覆盖父类方法地址,JVM通过虚方法表快速定位到子类的重写方法,实现"调用同一方法名,执行不同逻辑"的多态效果。

四、核心对比:方法重写(Override)vs 方法重载(Overload) 🆚

重写与重载是Java中两个易混淆的核心概念,两者本质、规则完全不同,必须清晰区分,是面试必考考点。

对比维度 方法重写(Override) 方法重载(Overload)
核心本质 子类对父类方法的重新实现 同一类中方法的同名多实现
存在范围 父子类之间(继承体系) 同一类中(或子类继承父类方法后重载)
方法签名 方法名、参数列表完全一致 方法名相同,参数列表不同(个数/类型/顺序)
返回值类型 需兼容(一致或子类协变) 无限制,可任意修改
访问权限 不低于父类方法权限 无限制,可任意修改
静态方法支持 ❌ 不支持(静态方法不能重写) ✅ 支持(静态方法可重载)
核心作用 实现多态、个性化扩展 简化方法调用,适配不同参数

实战案例:同一类中同时存在重写与重载

java 复制代码
// 父类:Animal
public class Animal {
    // 父类方法:供子类重写
    public void eat() {
        System.out.println("动物在吃饭");
    }

    // 父类方法:供子类重载
    public void eat(String food) {
        System.out.println("动物在吃" + food);
    }
}

// 子类:Cat
public class Cat extends Animal {
    // 重写父类eat()方法(无参)
    @Override
    public void eat() {
        System.out.println("加菲猫在吃猫粮");
    }

    // 重载eat()方法(参数列表不同)
    public void eat(String food, int amount) {
        System.out.println("加菲猫在吃" + amount + "份" + food);
    }
}

// 测试
public class TestOverloadAndOverride {
    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.eat(); // 重写方法(无参)
        cat.eat("猫粮"); // 继承父类的重载方法(单参)
        cat.eat("猫条", 2); // 子类自身的重载方法(双参)
    }
}

五、高频误区&避坑指南 ⚠️

误区1:认为静态方法可以重写

❌ 错误认知:子类定义同名静态方法就是重写;

✅ 正确结论:静态方法属于类级别,无法重写,子类同名静态方法仅为"隐藏"父类方法,调用时优先执行当前类的静态方法(与对象无关,与类有关)。

误区2:省略@Override注解,忽略重写校验

❌ 错误示例:未加注解,重写方法签名错误却未发现;

java 复制代码
// 父类方法
public void eat(String food) {}
// 子类方法:参数类型错误,非重写,无报错提示
public void eat(int food) {}

✅ 正确做法:重写方法必加@Override注解,IDE会强制校验重写规则,签名错误时直接编译报错,避免逻辑错误。

误区3:重写方法缩小访问权限

❌ 错误示例:父类public方法,子类改为protected;

✅ 正确原则:重写方法权限只能"扩大或不变",优先使用与父类一致的权限(如父类public,子类也用public)。

误区4:混淆重写与变量隐藏

❌ 错误认知:重写与变量隐藏逻辑一致;

✅ 正确结论:方法重写是"虚方法表地址覆盖",调用时优先子类;变量隐藏是"就近原则",父类变量仍存在;super可访问被隐藏的父类变量,但无法直接访问被重写的父类方法(需用super.方法名())。

六、实战:重写方法的正确实现与错误排查 🕵️

问题代码:重写方法违反规则,编译报错

java 复制代码
// 父类:Person
public class Person {
    protected String getName() {
        return "人类";
    }

    public void show() throws IOException {
        System.out.println("展示信息");
    }
}

// 子类:Student
public class Student extends Person {
    // 错误1:返回值类型不兼容(String→int)
    @Override
    protected int getName() {
        return 1;
    }

    // 错误2:异常范围扩大(IOException→Exception)
    @Override
    public void show() throws Exception {
        System.out.println("学生展示信息");
    }
}

问题分析与修复

  1. 错误1:返回值类型从String改为int,不兼容父类返回值,需改为String类型;
  2. 错误2:异常从IOException扩大为Exception,需缩小异常范围或与父类一致。

修复后代码

java 复制代码
public class Student extends Person {
    // 修复1:返回值类型改为String,与父类一致
    @Override
    protected String getName() {
        return "学生";
    }

    // 修复2:异常改为与父类一致
    @Override
    public void show() throws IOException {
        System.out.println("学生展示信息");
    }
}

✍️ 写在最后

  1. 方法重写的核心是子类覆盖父类方法 ,遵循"统一接口、个性化实现",是多态的基础,重写方法必加@Override注解做校验;
  2. 重写6大规则必须牢记,尤其是"方法签名一致、权限不缩小、异常不扩大",违反则编译报错;
  3. 底层本质:重写依赖虚方法表地址覆盖,JVM通过虚方法表定位子类重写方法,实现多态调用;
  4. 核心区分:重写是父子类间的方法覆盖,重载是同一类中的同名多实现,两者规则、作用完全不同,切勿混淆。

下一篇我们将深入多态的核心------讲解Java多态的定义、实现条件与底层原理,结合实战案例展示多态在实际开发中的应用,让你彻底掌握面向对象的三大特性之一💪!


❤️ 我是黎雁,专注Java基础与实战分享,关注我,一起从0到1吃透Java面向对象!

📚 后续文章预告:《Java多态:定义+实现条件+底层原理+实战应用》

💬 评论区交流:你在重写方法时遇到过哪些规则报错?或者对重写与重载的区别还有疑问,欢迎留言讨论~

相关推荐
blueSatchel8 小时前
U-Boot载入到DDR过程的代码分析
linux·开发语言·u-boot
专注VB编程开发20年8 小时前
vb.net datatable新增数据时改用数组缓存
java·linux·windows
(>_<)8 小时前
java minio 分片上传工具类与测试demo
java·minio·分片上传
不想打工的码农8 小时前
MyBatis-Plus多数据源实战:被DBA追着改配置后,我肝出这份避坑指南(附动态切换源码)
java·后端
无小道8 小时前
QT——QFIie和QFileInfo文件类
开发语言·qt·命令模式
Coder_Boy_8 小时前
Deeplearning4j+ Spring Boot 电商用户复购预测案例
java·人工智能·spring boot·后端·spring
踢足球09299 小时前
寒假打卡:2026-2-7
java·开发语言·javascript
闻哥9 小时前
Kafka高吞吐量核心揭秘:四大技术架构深度解析
java·jvm·面试·kafka·rabbitmq·springboot
金牌归来发现妻女流落街头9 小时前
【Springboot基础开发】
java·spring boot·后端
考琪9 小时前
Nginx打印变量到log方法
java·运维·nginx