一、什么是方法重写?用大白话讲透核心
先给新手最易懂的定义:
方法重写 = 子类给父类的方法"换个新逻辑" + 保留原方法名
就像生活中的例子:
- 爸爸(父类)会做"西红柿炒蛋"(方法),步骤是"先炒蛋后炒西红柿"
- 儿子(子类)也会做"西红柿炒蛋"(同一个方法名),但改成了"先炒西红柿后炒蛋"(新逻辑)
- 外人喊"做西红柿炒蛋"(调用方法),爸爸和儿子会按自己的方式做,但方法名完全一样
对应到Java里:
- 父类定义通用方法(比如
eat()),子类继承后,写一个方法名、参数列表、返回值完全一样的方法,替换/扩展父类逻辑 - 核心关键词:
@Override(注解,标识这是重写方法) - 新手记住:重写是"父子类之间"的行为,方法名必须"一模一样",逻辑可以"全新定制"
二、为什么需要方法重写?先看反例(新手踩坑点)
先写一个「不用重写导致问题」的示例,新手一眼就能看出问题:
java
// 父类:动物类
class Animal {
// 通用方法:所有动物都会叫,但父类只能写通用逻辑
public void shout() {
System.out.println("动物发出叫声");
}
}
// 子类:狗类
class Dog extends Animal {
// 问题:想让狗叫"汪汪汪",但没有重写父类方法
// 只能新增一个方法,方法名和父类不一样,逻辑混乱
public void dogShout() {
System.out.println("狗汪汪汪叫");
}
}
// 子类:猫类
class Cat extends Animal {
// 同理:新增专属方法,方法名不统一
public void catShout() {
System.out.println("猫喵喵喵叫");
}
}
// 测试类
public class NoOverrideDemo {
public static void main(String[] args) {
Dog dog = new Dog();
dog.shout(); // 输出"动物发出叫声"(不是想要的效果)
dog.dogShout(); // 必须调用专属方法,麻烦且不统一
Cat cat = new Cat();
cat.shout(); // 输出"动物发出叫声"
cat.catShout(); // 调用专属方法
}
}
问题分析:
- 逻辑不统一:所有动物都有"叫"的行为,但子类要新增不同名的方法(
dogShout/catShout),调用时没有统一标准 - 代码冗余:如果有10种动物,就要写10个不同名的"叫"方法,维护成本高
- 违背继承设计:继承的核心是"复用+扩展",但这里没有扩展父类方法,而是重新造方法
三、方法重写的核心规则(新手必记)
方法重写有5个核心规则,记准了就不会错:
- 方法签名完全一致:方法名、参数列表(个数、类型、顺序)、返回值必须和父类一模一样
- 访问权限不能更严格 :父类是
public,子类不能是private/protected(新手先记:都用public) - 不能重写父类的private方法:父类私有的方法子类看不见,没法重写
- 抛出的异常不能更宽泛:(新手暂时不用记,入门阶段先关注核心规则)
- 建议加@Override注解:不是必须,但加了编译器会帮你检查是否符合重写规则,写错了直接报错
四、方法重写的完整代码示例(带详细注释)
java
// 父类:动物类(定义通用方法)
class Animal {
// 父类通用方法:动物叫(通用逻辑)
public void shout() {
System.out.println("动物发出叫声");
}
// 父类通用方法:动物吃食物(带参数)
public void eat(String food) {
System.out.println("动物吃" + food);
}
// 父类private方法:子类无法重写
private void sleep() {
System.out.println("动物睡觉");
}
// 父类返回值为String的方法(测试返回值一致规则)
public String getType() {
return "普通动物";
}
}
// 子类1:狗类(重写父类方法)
class Dog extends Animal {
// 1. 重写父类的shout方法(核心示例)
@Override // 注解:标识重写,写错会报错(比如方法名写成shouts)
public void shout() {
// 保留父类逻辑(可选):调用父类原版方法
super.shout();
// 新增子类专属逻辑
System.out.println("狗汪汪汪叫");
}
// 2. 重写带参数的eat方法
@Override
public void eat(String food) {
System.out.println("狗啃着吃" + food);
}
// 3. 重写返回值为String的方法
@Override
public String getType() {
return "犬类"; // 返回值类型必须和父类一致(都是String)
}
// 错误示范:试图重写父类private方法(编译不报错,但这不是重写,只是子类新增方法)
public void sleep() {
System.out.println("狗趴着睡觉");
}
}
// 子类2:猫类(重写父类方法)
class Cat extends Animal {
// 重写shout方法(纯自定义逻辑,不保留父类)
@Override
public void shout() {
System.out.println("猫喵喵喵叫");
}
// 重写eat方法
@Override
public void eat(String food) {
System.out.println("猫舔着吃" + food);
}
}
// 测试类:验证方法重写效果
public class MethodOverrideDemo {
public static void main(String[] args) {
// ========== 测试狗类重写 ==========
System.out.println("--- 测试狗类重写 ---");
Dog dog = new Dog();
dog.shout(); // 先执行父类shout,再执行子类重写的逻辑
dog.eat("骨头"); // 执行子类重写的eat方法
System.out.println("狗的类型:" + dog.getType()); // 执行子类重写的getType
System.out.println("\n--- 测试猫类重写 ---");
// ========== 测试猫类重写 ==========
Cat cat = new Cat();
cat.shout(); // 只执行子类重写的shout逻辑
cat.eat("小鱼干"); // 执行子类重写的eat方法
// ========== 测试重写规则:private方法不能重写 ==========
System.out.println("\n--- 测试private方法 ---");
dog.sleep(); // 执行子类新增的sleep方法,不是重写
}
}
代码运行结果
--- 测试狗类重写 ---
动物发出叫声
狗汪汪汪叫
狗啃着吃骨头
狗的类型:犬类
--- 测试猫类重写 ---
猫喵喵喵叫
猫舔着吃小鱼干
--- 测试private方法 ---
狗趴着睡觉
五、核心知识点解释(新手必懂)
1. @Override注解的作用(新手必加)
- 核心作用:语法校验
- 如果你的方法不符合重写规则(比如方法名拼错、参数列表不一样),编译器会直接报错
- 示例:如果把
@Override下的shout()写成shouts(),会提示"Method does not override method from superclass"
- 新手理解:就像写作业时的"检查器",帮你避免低级错误
2. 方法重写vs方法重载(新手最易混淆,对比记忆)
这是Java入门最核心的两个概念,用表格对比,一看就懂:
| 特性 | 方法重写(Override) | 方法重载(Overload) |
|---|---|---|
| 发生位置 | 父子类之间 | 同一个类中 |
| 方法名 | 必须完全一致 | 必须完全一致 |
| 参数列表 | 必须完全一致(个数/类型/顺序) | 必须不一样(个数/类型/顺序) |
| 返回值 | 必须完全一致(新手阶段) | 可以不一样 |
| 访问权限 | 不能比父类更严格 | 无要求 |
| 注解 | 可用@Override | 无专属注解 |
3. 重写的常见场景(新手能理解)
- 定制化行为:父类方法是通用逻辑,子类按自己的特性修改(比如动物叫、吃食物)
- 扩展父类逻辑:保留父类方法的核心逻辑,新增子类专属逻辑(比如狗叫先执行父类"动物叫",再加"汪汪汪")
- 统一调用标准 :所有子类都重写同一个父类方法,调用时不用记不同的方法名(比如
shout(),不管猫狗都能调)
4. 新手避坑点
- 坑1:以为"方法名一样就是重写"→ 必须参数列表、返回值也一样,否则是重载或新增方法
- 坑2:重写父类public方法时,子类写成private → 编译报错(访问权限不能更严格)
- 坑3:试图重写父类private方法 → 其实是子类新增方法,不是重写(编译器不报错,但逻辑错了)
- 坑4:忘记加@Override → 写错了编译器不提醒,容易埋下BUG
六、方法重写的实际应用场景(新手能理解)
- 框架开发 :比如SpringMVC中,你写的
Controller类重写框架提供的handleRequest方法,定制自己的请求处理逻辑 - 工具类扩展 :比如父类是"图形工具类",有
calculateArea()(计算面积)方法,子类"圆形类""矩形类"重写该方法,实现各自的面积计算 - 多态实现:方法重写是多态的基础(后续会讲),比如用父类引用指向子类对象,调用重写方法时,会执行子类的逻辑
七、常见面试题(新手提前了解)
- 问 :方法重写的核心规则是什么?
答:方法名、参数列表、返回值必须和父类一致;访问权限不能比父类更严格;不能重写父类private方法。 - 问 :@Override注解有什么用?
答:校验方法是否符合重写规则,写错时编译器报错,避免低级错误,提高代码可读性。 - 问 :方法重写和方法重载的核心区别?
答:重写发生在父子类之间,参数列表必须一致;重载发生在同一个类中,参数列表必须不同。
总结
- 方法重写是子类对父类"同名方法"的定制化改造,核心要求是方法签名(名+参数+返回值)完全一致
- @Override注解是重写的"检查器",新手必须加,能避免大部分低级错误
- 重写和重载的核心区别:重写在父子类、参数一致;重载在本类、参数不同
新手学习建议
- 先复制代码运行,重点看"保留父类逻辑"和"纯自定义逻辑"两种重写方式的区别
- 故意写错重写规则(比如改参数列表、改访问权限),看编译器报什么错,加深记忆
- 练习:写一个"交通工具类(父类)→ 汽车类/飞机类(子类)",重写
run()方法,实现各自的运行逻辑