Java 方法重写(Override)详解:从概念到实战
·
1. 什么是方法重写?
方法重写(Override)是面向对象编程中多态性的核心体现之一。它允许子类重新定义从父类继承而来的方法,以提供更适合自身特性的实现。
核心定义:在继承关系中,子类定义一个与父类方法签名(方法名、参数列表)完全相同的方法,从而覆盖父类的原有实现。
2. 方法重写 vs 方法重载
初学者常混淆方法重写(Override)与方法重载(Overload),下表清晰对比了两者的区别:
| 对比维度 | 方法重写 (Override) | 方法重载 (Overload) |
|---|---|---|
| 发生位置 | 子类与父类之间(继承关系) | 同一个类内部 |
| 方法签名 | 必须完全相同(方法名、参数列表) | 必须不同(参数类型、个数或顺序) |
| 返回类型 | 相同或是其子类(协变返回类型) | 可以不同 |
| 访问权限 | 不能比父类方法更严格 | 没有限制 |
| 抛出异常 | 不能抛出比父类方法更宽泛的检查异常 | 没有限制 |
| 核心目的 | 实现多态,提供子类特定行为 | 提供同一功能的不同调用方式 |
3. 方法重写的规则与要求
要成功重写一个方法,必须遵循 Java 语言的严格规则:
- 签名一致:方法名、参数列表(类型、顺序、数量)必须与父类方法完全相同。
- 返回类型:必须相同,或是父类方法返回类型的子类(协变返回类型)。
- 访问修饰符:子类方法的访问权限不能比父类方法更严格(例如,父类是
protected,子类可以是protected或public,但不能是private或默认包权限)。 - 异常声明:子类方法抛出的检查异常(checked exception)不能比父类方法声明的异常更宽泛(可以是其子类或不抛出)。
- 非静态方法:只能重写实例方法,不能重写静态方法(静态方法隐藏是另一概念)。
- final 方法:被
final修饰的方法不能被重写。
4. @Override 注解
强烈建议在重写方法上使用 @Override 注解。它的作用包括:
- 编译器检查:确保该方法确实是重写父类方法,如果签名不匹配,编译器会报错。
- 代码可读性:明确标识出这是一个重写方法,便于阅读和维护。
class Animal {
public void makeSound() {
System.out.println("动物发出声音");
}
}
class Dog extends Animal {
@Override // 使用注解,清晰表明这是重写
public void makeSound() {
System.out.println("汪汪汪!");
}
}
5. 实战代码示例
下面通过一个完整的例子演示方法重写的应用:
// 父类:图形
class Shape {
protected double area;
// 计算面积的方法,被子类重写
public double calculateArea() {
System.out.println("计算图形面积(基类默认实现)");
return 0.0;
}
public void displayInfo() {
System.out.println("这是一个图形");
}
}
// 子类:圆形
class Circle extends Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
// 重写 calculateArea 方法,提供圆面积的具体计算
@Override
public double calculateArea() {
area = Math.PI * radius * radius;
System.out.println("圆形面积: " + area);
return area;
}
// 重写 displayInfo 方法,增加圆形特有信息
@Override
public void displayInfo() {
super.displayInfo(); // 调用父类方法
System.out.println("图形类型: 圆形,半径: " + radius);
}
}
// 子类:矩形
class Rectangle extends Shape {
private double width;
private double height;
public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
public double calculateArea() {
area = width * height;
System.out.println("矩形面积: " + area);
return area;
}
@Override
public void displayInfo() {
System.out.println("图形类型: 矩形,宽: " + width + ", 高: " + height);
}
}
// 测试类
public class OverrideDemo {
public static void main(String[] args) {
Shape shape1 = new Circle(5.0);
Shape shape2 = new Rectangle(4.0, 6.0);
// 多态调用:编译时类型为 Shape,运行时调用各自子类重写的方法
shape1.calculateArea(); // 输出: 圆形面积: 78.53981633974483
shape1.displayInfo(); // 输出: 这是一个图形\n图形类型: 圆形,半径: 5.0
shape2.calculateArea(); // 输出: 矩形面积: 24.0
shape2.displayInfo(); // 输出: 图形类型: 矩形,宽: 4.0, 高: 6.0
// 父类引用,子类对象 - 多态的经典体现
Shape[] shapes = {new Circle(3), new Rectangle(2, 5)};
for (Shape s : shapes) {
s.calculateArea(); // 根据实际对象类型调用对应方法
}
}
}
6. 常见面试题与易错点
- Q: 重写 private 方法可以吗?
A: 不可以。private 方法对子类不可见,因此在子类中声明一个同名方法不是重写,而是定义了一个全新的方法。 - Q: 静态方法能被重写吗?
A: 不能。静态方法属于类,调用时取决于编译时类型,不存在多态。子类可以定义同名同参的静态方法,但这叫“方法隐藏”(Method Hiding)。 - Q: 构造方法能被重写吗?
A: 不能。构造方法不是继承的,每个类必须定义自己的构造方法。 - Q: 重写方法时,子类方法可以改变参数类型吗?
A: 不可以。改变参数类型意味着方法签名不同,这不是重写,而是重载(如果发生在同一类)或新方法(如果发生在子类)。
7. 总结
方法重写是实现运行时多态的关键机制,它让子类能够定制继承自父类的行为。掌握重写的规则、正确使用 @Override 注解、理解其与重载的区别,是编写高质量、可扩展 Java 面向对象代码的基础。在实际开发中,合理运用方法重写可以大幅提升代码的灵活性和可维护性。
更多推荐


所有评论(0)