方法重写概述
方法重写(Method Overriding)是面向对象编程的核心特性之一
学习目标
理解方法重写的概念、作用及与重载的区别,掌握正确的重写语法
什么是方法重写?
方法重写是指子类重新定义父类中已有的方法,提供与父类不同的实现。
特点:
- 发生在子类与父类之间
- 方法名、参数列表完全相同
- 返回类型相同或是其子类型
- 访问权限不能更严格
重写 vs 重载
区别点 | 方法重写 | 方法重载 |
---|---|---|
发生位置 | 子类与父类之间 | 同一个类中 |
参数列表 | 必须相同 | 必须不同 |
返回类型 | 相同或子类型 | 可以不同 |
访问修饰符 | 不能更严格 | 可以不同 |
方法重写规则详解
掌握方法重写的具体规则和限制条件
1
方法签名必须相同
方法名、参数列表(类型、顺序、数量)必须完全一致
public class Animal {
public void makeSound() {
System.out.println("动物叫声");
}
}
public class Dog extends Animal {
@Override
public void makeSound() { // 正确:签名完全相同
System.out.println("汪汪!");
}
}
2
访问权限规则
子类方法的访问权限不能比父类方法更严格
public class Parent {
protected void display() { } // protected
}
public class Child extends Parent {
@Override
public void display() { } // 正确:public > protected
}
3
返回类型协变
返回类型可以是父类方法返回类型的子类型
public class Animal {
public Animal getInstance() {
return new Animal();
}
}
public class Dog extends Animal {
@Override
public Dog getInstance() { // 正确:Dog是Animal的子类
return new Dog();
}
}
4
异常声明规则
重写方法抛出的异常范围不能大于父类方法
import java.io.*;
public class Parent {
public void read() throws IOException { }
}
public class Child extends Parent {
@Override
public void read() throws FileNotFoundException { } // 正确:范围更小
}
@Override注解详解
了解@Override注解的作用和使用场景
注解作用
- 告诉编译器这是一个重写方法
- 编译器会检查是否符合重写规则
- 提高代码可读性和安全性
- 帮助发现拼写错误或签名不匹配
使用示例
public class Employee {
public String getDetails() {
return "员工信息";
}
}
public class Manager extends Employee {
@Override // 编译器会验证这个方法是否正确重写了父类方法
public String getDetails() {
return "经理信息:奖金+" + bonus;
}
}
不使用@Override的风险
如果不使用@Override注解,当方法签名有误时,编译器会认为这是一个新方法,而不是重写,导致运行时行为不符合预期。
实战案例
通过实际案例理解方法重写的应用
1
形状类层次结构
创建一个几何图形类层次结构,实现面积计算的方法重写
// 父类:Shape.java
public abstract class Shape {
protected String color;
public Shape(String color) {
this.color = color;
}
public abstract double calculateArea();
public String getInfo() {
return "这是一个" + color + "的形状";
}
}
// 子类:Circle.java
public class Circle extends Shape {
private double radius;
public Circle(String color, double radius) {
super(color);
this.radius = radius;
}
@Override
public double calculateArea() {
return Math.PI * radius * radius;
}
@Override
public String getInfo() {
return super.getInfo() + ",半径:" + radius;
}
}
// 子类:Rectangle.java
public class Rectangle extends Shape {
private double width, height;
public Rectangle(String color, double width, double height) {
super(color);
this.width = width;
this.height = height;
}
@Override
public double calculateArea() {
return width * height;
}
}
2
测试类
public class ShapeTest {
public static void main(String[] args) {
Shape circle = new Circle("红色", 5.0);
Shape rectangle = new Rectangle("蓝色", 4.0, 6.0);
System.out.println(circle.getInfo() + ",面积:" + circle.calculateArea());
System.out.println(rectangle.getInfo() + ",面积:" + rectangle.calculateArea());
}
}
运行结果
程序输出:
这是一个红色的形状,半径:5.0,面积:78.53981633974483
这是一个蓝色的形状,面积:24.0
常见错误与解决方案
避免方法重写中的常见陷阱
错误1:方法签名不匹配
public class Parent {
public void print(String msg) { }
}
public class Child extends Parent {
// 错误:参数类型不匹配,这不是重写
public void print(Object msg) { }
}
解决方法:确保方法名和参数列表完全相同
错误2:访问权限更严格
public class Parent {
public void show() { }
}
public class Child extends Parent {
// 错误:protected比public更严格
protected void show() { }
}
解决方法:子类方法的访问权限必须大于或等于父类方法
错误3:final方法被重写
public class Parent {
public final void display() { }
}
public class Child extends Parent {
// 错误:final方法不能被重写
public void display() { }
}
解决方法:final方法不能被重写,考虑使用其他方法名
错误4:静态方法重写
public class Parent {
public static void staticMethod() { }
}
public class Child extends Parent {
// 这不是重写,而是隐藏(hiding)
public static void staticMethod() { }
}
注意:静态方法不能被重写,这称为方法隐藏(method hiding)
最佳实践总结
方法重写的黄金法则和实用建议
必须遵循的规则
- 始终使用@Override注解
- 保持方法签名完全一致
- 返回类型相同或协变
- 访问权限不能更严格
- 异常范围不能更大
设计建议
- 重写时调用super.method()保留父类行为
- 在Javadoc中说明重写行为
- 考虑使用模板方法模式
- 保持方法语义的一致性
实战练习
完成以下练习巩固方法重写知识:
- 创建一个BankAccount类,包含deposit()和withdraw()方法
- 创建SavingsAccount子类重写withdraw()方法,添加透支保护
- 创建CreditAccount子类重写withdraw()方法,实现信用额度检查
- 使用多态测试不同账户类型的行为
知识清单
- 理解方法重写的概念和作用
- 掌握方法重写的5大规则
- 熟练使用@Override注解
- 识别并避免常见重写错误
- 能够在实际项目中正确使用方法重写