Java 方法重写详解:规则、多态调用与 super 协作
方法重写允许子类提供父类方法的特定实现,是运行时多态的基础。重写方法需遵守严格契约,否则编译报错。
重写基础示例
class Animal { void move() { System.out.println("动物会动"); } }
class Dog extends Animal {
@Override void move() { System.out.println("狗会跑和走"); }
}
Animal a = new Animal(); a.move(); // 动物会动
Animal b = new Dog(); b.move(); // 狗会跑和走(动态分派)
编译期看引用类型(Animal 有 move),运行期看对象实际类型(Dog 的 move)。
引用类型限制
Animal b = new Dog();
b.move(); // ✅ Animal 有 move
b.bark(); // ❌ 编译错误:Animal 无 bark 方法
父类引用只能调用父类声明的方法,子类新增方法需向下转型或重新设计。
重写九大铁律
| # | 规则 | 说明 |
|---|---|---|
| 1 | 参数列表完全一致 | 顺序、类型、数量均相同 |
| 2 | 返回类型兼容 | 相同或协变返回类型(子类型) |
| 3 | 访问权限不降低 | public > protected > 默认 > private;子类权限 ≥ 父类 |
| 4 | 仅实例方法可重写 | 静态方法属类不属对象,只能隐藏 |
| 5 | final 方法不可重写 | 编译报错 |
| 6 | static 方法不可重写 | 可重新声明(隐藏),非重写 |
| 7 | 不可继承则不可重写 | private 方法子类不可见 |
| 8 | 跨包重写限制 | 仅可重写 public/protected 非 final 方法 |
| 9 | 异常声明收窄 | 可抛出更少/更具体受检异常;非受检异常无限制 |
super 调用父类实现
子类重写中调用 super.method() 可复用父类逻辑,实现扩展而非完全替换。
class Dog extends Animal {
@Override void move() {
super.move(); // 先执行父类逻辑
System.out.println("狗会跑和走"); // 再添加子类行为
}
}
// 输出:
// 动物会动
// 狗会跑和走
重写 vs 重载对比
| 维度 | 重写 | 重载 |
|---|---|---|
| 发生位置 | 父子类 | 同一类 |
| 方法签名 | 完全相同 | 参数列表不同 |
| 返回类型 | 兼容/协变 | 可任意 |
| 绑定时机 | 运行时(动态) | 编译时(静态) |
| 多态性 | 体现运行时多态 | 编译时多态 |
最佳实践
- 始终加
@Override注解,编译器校验防止误写 - 谨慎重写:优先考虑组合/策略模式替代深层继承重写
- 文档化重写契约:前置/后置条件、副作用、线程安全性
- 避免在构造器中调用可重写方法(子类字段未初始化)
java
- 精通 Java 运算符:类型、语法与实战示例
- 精通 Java 接口:概念、实现与最佳实践
- 精通 Java Try-With-Resources:自动资源管理详解
- Java 注解详解:类型、放置位置与实战示例
- Java String length() 方法:获取字符串长度(示例)
- 精通 Java String.indexOf():定位子字符串与实战示例
- Java String.charAt() 详解:语法、返回类型、异常与实战示例
- 精通 Java String compareTo():语法、用例与实战示例
- Java String.contains() 方法:检查子字符串是否存在(实战示例)
- 精通 Java String.endsWith():检查字符串后缀(示例)
- Java 字符串替换大全:replace()、replaceAll() 与 replaceFirst() 详解
- Java static 详解:静态变量、方法、代码块与实战示例