
🏠个人主页:黎雁
🎬作者简介:C/C++/JAVA后端开发学习者
❄️个人专栏:C语言、数据结构(C语言)、EasyX、JAVA、游戏、规划、程序人生
✨ 从来绝巘须孤往,万里同尘即玉京

文章目录
- Java方法重写Override:规则+底层本质+与重载区别
-
- [📝 文章摘要](#📝 文章摘要)
- [一、方法重写是什么?定义与核心作用 📖](#一、方法重写是什么?定义与核心作用 📖)
-
- [1.1 方法重写的官方定义](#1.1 方法重写的官方定义)
- [1.2 核心作用:实现"多态"与"个性化扩展"](#1.2 核心作用:实现“多态”与“个性化扩展”)
-
- 实战案例:动物类体系的方法重写
- 运行结果
- [核心亮点 ✨](#核心亮点 ✨)
- 二、方法重写的6大核心规则(必记)✅
- [三、底层本质:虚方法表的覆盖机制 🧠](#三、底层本质:虚方法表的覆盖机制 🧠)
-
- [3.1 重写前:父类与子类的虚方法表](#3.1 重写前:父类与子类的虚方法表)
- [3.2 重写后:虚方法表的覆盖](#3.2 重写后:虚方法表的覆盖)
- [3.3 方法调用时的底层流程](#3.3 方法调用时的底层流程)
- [四、核心对比:方法重写(Override)vs 方法重载(Overload) 🆚](#四、核心对比:方法重写(Override)vs 方法重载(Overload) 🆚)
- [五、高频误区&避坑指南 ⚠️](#五、高频误区&避坑指南 ⚠️)
- [六、实战:重写方法的正确实现与错误排查 🕵️](#六、实战:重写方法的正确实现与错误排查 🕵️)
- [✍️ 写在最后](#✍️ 写在最后)

Java方法重写Override:规则+底层本质+与重载区别
✨ 知识回顾
上一篇我们掌握了继承中成员变量的访问逻辑,通过"就近原则"解决了变量查找优先级问题,还学会用this和super精准访问子类、父类变量,理清了同名变量的"隐藏"特性。这篇我们聚焦继承中方法的核心特性------方法重写(Override),它是实现多态的基础,也是高频考点。我们会从定义、规则、底层本质入手,结合实战案例区分"重写"与"重载",帮你彻底吃透方法重写的核心逻辑🚀!
📝 文章摘要
- 核心摘要:本文讲解方法重写的定义、核心作用,拆解重写的6大语法规则,深入剖析虚方法表覆盖的底层原理,通过实战案例验证规则,同时对比方法重写与方法重载的核心区别,帮你精准掌握重写的用法,规避常见错误。
- 阅读时长:10分钟
- 适合人群&阅读重点
🎯 Java初学者:重点牢记重写的语法规则,能正确实现子类对父类方法的重写,区分重写与重载。
📚 高校计算机专业学生:从虚方法表角度理解重写的底层本质,掌握面向对象多态的实现原理。
💻 初级开发工程师:规范重写方法的编写,解决重写引发的方法调用异常,提升代码的扩展性。
📖 面试备考者:熟记重写规则、底层原理及与重载的区别,应对"重写vs重载""重写规则"类面试题。
一、方法重写是什么?定义与核心作用 📖
1.1 方法重写的官方定义
方法重写(Override) 是指在继承体系中,子类定义了一个与父类方法名、参数列表、返回值类型完全一致的非私有成员方法,子类方法会覆盖父类方法,当调用该方法时,优先执行子类的重写方法,而非父类原方法。
简单来说:重写是子类对父类方法的"重新实现",保留方法签名(方法名+参数列表),修改方法体逻辑,适配子类的个性化需求。
1.2 核心作用:实现"多态"与"个性化扩展"
重写的核心价值的是统一接口、个性化实现,让不同子类对同一方法有不同的执行逻辑,这是Java多态特性的基础。
实战案例:动物类体系的方法重写
父类Animal定义通用方法eat(),子类Cat和Dog重写该方法,实现各自的吃饭逻辑:
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的重写方法
}
}
运行结果
加菲猫在吃猫粮
哈士奇在吃狗粮
核心亮点 ✨
- 统一接口:所有子类都遵循
eat()方法签名,调用方式一致; - 个性化实现:不同子类的
eat()逻辑不同,适配自身特性; - 注解增强:
@Override注解是重写的规范标识,可强制校验重写规则(不符合则编译报错),推荐必加。
二、方法重写的6大核心规则(必记)✅
方法重写有严格的语法限制,违反任意一条都会编译报错,这是高频考点,必须逐条牢记:
规则1:方法签名完全一致
子类重写方法的方法名、参数列表 必须与父类方法完全一致(参数个数、类型、顺序都不能变),否则不构成重写(可能是重载)。
❌ 错误示例:参数列表不同,不构成重写
java
// 父类方法
public void eat(String food) {}
// 子类方法:参数类型不同,非重写
public void eat(int num) {}
规则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的执行步骤:
- 找到
Cat对象的引用,获取其对应的虚方法表; - 在虚方法表中查找
eat()方法的地址; - 执行该地址指向的方法(子类重写后的
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:返回值类型从
String改为int,不兼容父类返回值,需改为String类型; - 错误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("学生展示信息");
}
}
✍️ 写在最后
- 方法重写的核心是子类覆盖父类方法 ,遵循"统一接口、个性化实现",是多态的基础,重写方法必加
@Override注解做校验; - 重写6大规则必须牢记,尤其是"方法签名一致、权限不缩小、异常不扩大",违反则编译报错;
- 底层本质:重写依赖虚方法表地址覆盖,JVM通过虚方法表定位子类重写方法,实现多态调用;
- 核心区分:重写是父子类间的方法覆盖,重载是同一类中的同名多实现,两者规则、作用完全不同,切勿混淆。
下一篇我们将深入多态的核心------讲解Java多态的定义、实现条件与底层原理,结合实战案例展示多态在实际开发中的应用,让你彻底掌握面向对象的三大特性之一💪!
❤️ 我是黎雁,专注Java基础与实战分享,关注我,一起从0到1吃透Java面向对象!
📚 后续文章预告:《Java多态:定义+实现条件+底层原理+实战应用》
💬 评论区交流:你在重写方法时遇到过哪些规则报错?或者对重写与重载的区别还有疑问,欢迎留言讨论~