Java·如何区别多态中的“重写”与“重载”。
我们用两个形象的生活例子,再搭配代码帮助分清两者关系。
一、核心比喻
- 重载(Overload):像「同一家奶茶店的 “不同套餐”」—— 店名(方法名)相同,但配料、规格(参数)不同,价格(返回值)可不一样,点单时选对应套餐(编译时确定)。
- 重写(Override):像「儿子继承父亲的 “店铺”,但改了经营方式」—— 店铺名(方法名)、经营范围(参数)不变,但做事流程(实现逻辑)不一样,顾客上门才知道实际服务(运行时确定)。
二、分点详解(生活例子 + 代码例子)
1. 重载(Overload):“同名不同参,同一类里的多选择”
核心定义
同一个类(或父子类)中,方法名相同,但参数列表不同(参数个数、类型、顺序任意一个不同)的多个方法,称为重载。
✅ 关键:只看「方法名 + 参数列表」,和返回值、访问权限无关;编译时就确定调用哪个方法(静态绑定)。
形象生活例子:奶茶店的 “珍珠奶茶” 套餐
假设一家奶茶店的招牌是 “珍珠奶茶”(方法名 makePearlMilkTea),但提供 3 种套餐:
- 套餐 1:默认款(无参数)→ 中杯、少糖、无加料;
- 套餐 2:选甜度(1 个参数:甜度等级)→ 中杯、指定甜度、无加料;
- 套餐 3:选甜度 + 加料(2 个参数:甜度等级 + 加料类型)→ 中杯、指定甜度 + 加料。
顾客点单时,只要说 “要珍珠奶茶”,再补充需求(参数),店员就知道做哪种 —— 这就是重载:同一个 “服务名”,不同 “需求参数” 对应不同 “服务结果”。
// 奶茶店类(同一类中重载)
class MilkTeaShop {// 重载1:无参数(默认套餐)public String makePearlMilkTea() {return "中杯珍珠奶茶 + 少糖 + 无加料";}// 重载2:1个参数(指定甜度)public String makePearlMilkTea(int sugarLevel) {return "中杯珍珠奶茶 + " + sugarLevel + "分糖 + 无加料";}// 重载3:2个参数(指定甜度+加料)public String makePearlMilkTea(int sugarLevel, String topping) {return "中杯珍珠奶茶 + " + sugarLevel + "分糖 + 加料:" + topping;}// 注意:仅返回值不同,不算重载(编译报错)// public int makePearlMilkTea(int sugarLevel) { ... }
}// 测试重载:编译时确定调用哪个方法
public class OverloadDemo {public static void main(String[] args) {MilkTeaShop shop = new MilkTeaShop();System.out.println(shop.makePearlMilkTea()); // 调用无参重载System.out.println(shop.makePearlMilkTea(7)); // 调用1个参数重载System.out.println(shop.makePearlMilkTea(5, "椰果")); // 调用2个参数重载}
}重载的关键特点
- 发生在「同一个类或父子类」中;
- 方法名必须相同,参数列表必须不同(个数、类型、顺序,只要一个不同即可);
- 返回值、访问权限可以不同;
- 编译时绑定(调用哪个方法,编译期就确定了)。
2. 重写(Override):“同名同参同签名,子类改写父类逻辑”
核心定义
子类继承父类后,对父类的「非静态、非 final、非 private 方法」进行改写 ——方法名、参数列表、返回值(协变除外)完全一致,只有方法体(实现逻辑)不同,称为重写。
✅ 关键:必须满足 “方法签名完全一致”,依赖继承关系;运行时才确定调用哪个子类的实现(动态绑定,多态的核心)。
形象生活例子:父子开 “早餐店”
父亲开了一家早餐店,核心业务是 “做包子”(父类方法 makeBun()),做法是 “猪肉馅 + 蒸 10 分钟”;
儿子继承了这家店(子类继承父类),但不想做猪肉馅,改成了 “牛肉馅 + 蒸 12 分钟”—— 店铺名(方法名)、业务(做包子,参数列表)没变,但做法(实现逻辑)改了;
顾客上门说 “要包子”(调用 makeBun()),如果是父亲的店,吃猪肉馅;如果是儿子的店,吃牛肉馅 —— 这就是重写:子类继承父类的 “行为规范”,但改了 “执行细节”。
// 父类:早餐店(定义核心行为)
class BreakfastShop {// 父类方法:做包子(方法签名:makeBun(),无参数,返回String)public String makeBun() {return "父亲的店:猪肉馅包子 + 蒸10分钟";}
}// 子类:儿子的早餐店(继承父类,重写方法)
class SonBreakfastShop extends BreakfastShop {// 重写:方法名、参数列表、返回值完全和父类一致,只改方法体@Override // 注解:强制检查是否合法重写(推荐用)public String makeBun() {return "儿子的店:牛肉馅包子 + 蒸12分钟";}
}// 测试重写:运行时确定调用哪个实现(多态)
public class OverrideDemo {public static void main(String[] args) {BreakfastShop shop1 = new BreakfastShop(); // 父类对象BreakfastShop shop2 = new SonBreakfastShop(); // 父类引用指向子类对象(多态)System.out.println(shop1.makeBun()); // 输出:父亲的店:猪肉馅包子 + 蒸10分钟System.out.println(shop2.makeBun()); // 输出:儿子的店:牛肉馅包子 + 蒸12分钟(运行时绑定子类实现)}
}重写的关键特点
- 发生在「子类和父类 / 接口」之间(必须有继承 / 实现关系);
- 方法签名(方法名 + 参数列表)必须完全一致;
- 返回值:基本类型必须相同,引用类型支持 “协变”(子类返回值是父类返回值的子类);
- 访问权限:子类方法不能比父类更严格(父类 public,子类不能是 protected/private);
- 运行时绑定(调用哪个方法,运行期才确定,依赖对象实际类型)。
3.重写 vs 重载 核心区别对比表

4.一句话口诀
- 重载:同名不同参,编译时定(选套餐)
- 重写:同名同参同签名,运行时定(改做法)
只要记住:“参数不同是重载,父子同名同参是重写”,再结合奶茶店和早餐店的例子,就不会搞混了。
