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多态:定义+实现条件+底层原理+实战应用》

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

相关推荐
猿小羽2 小时前
Spring AI + MCP 实战:构建标准化 AI 智能代理与上下文集成
java·spring boot·llm·ai agent·spring ai·anthropic·mcp
高山上有一只小老虎2 小时前
mybatisplus分页查询版本 3.5.8 以下和版本 3.5.9及以上的区别
java·spring boot·mybatis
王同学 学出来2 小时前
React实操案例(四)
开发语言·react.js·前端框架
哪里不会点哪里.2 小时前
Spring Boot 项目搭建过程
java·spring boot·后端
李少兄2 小时前
FHIR 资源查询实战指南:从 HTTP 接口到 Java 客户端的完整实现
java·网络协议·http
zhengfei6112 小时前
一种综合性的现代架构模型,用于集成平台解决方案和工具,以支持专业的红队。
开发语言·人工智能·网络安全·架构·信息与通信
Stecurry_302 小时前
Spring Boot 深度进阶:从配置管理到生产级实践
java·spring boot·后端
zuoyou-HPU2 小时前
QT C++开发知识点剖析
开发语言·c++·qt
人道领域2 小时前
javaWeb从入门到进阶(MyBatis拓展)
java·tomcat·mybatis