重写方法的访问修饰符不能比父类更严格,必须保持方法签名一致(含协变返回类型),static/final/private方法不可重写,且强烈建议使用@Override注解以避免编译期错误。

重写方法的访问修饰符不能比父类更严格
子类重写方法时,public 可以重写 protected 或 default(包级私有),但反过来不行。比如父类是 protected void doWork(),子类不能用 private void doWork() —— 编译直接报错:Cannot reduce the visibility of the inherited method。
常见误操作:
- 父类方法是
public,子类写成protected或default→ 编译失败 - 父类是
default(没写修饰符),子类在不同包里尝试重写 → 根本看不见该方法,谈不上重写
方法签名必须完全一致:名称、参数列表、返回类型(协变除外)
Java 要求重写方法的名称和参数列表(类型、顺序、数量)与父类一模一样。return 类型通常也要相同,但有一个例外:允许使用**协变返回类型**(covariant return type),即子类方法可返回父类返回类型的子类型。
例如:
立即学习“Java免费学习笔记(深入)”;
class Animal {}
class Dog extends Animal {}
class Base {
Animal getAnimal() { return new Animal(); }
}
class Sub extends Base {
@Override
Dog getAnimal() { return new Dog(); } // ✅ 合法:Dog 是 Animal 的子类
}
但以下都不行:
-
getAnimal(String name)重写getAnimal()→ 参数变了,是重载,不是重写 -
Object getAnimal()重写Animal getAnimal()→ 返回类型不兼容,编译报错 - 参数类型用泛型擦除后相同但声明不同,如
ListvsList→ 擦除后都是List,但编译仍拒绝,因为签名不等价
@Override 注解不是必须的,但强烈建议加上
不加 @Override 不影响运行时行为,但它能帮你在编译期捕获很多典型错误:
- 父类方法改名了,子类没同步 → 加了注解会立刻报错:
method does not override or implement a method from a supertype - 参数类型写错,比如把
int写成Integer→ 编译器提示无法匹配父类方法 - 父类方法被改成
private或static→ 子类同名方法变成独立方法,加注解会报警
没加 @Override 时,这些错误可能潜伏到运行时才暴露(比如多态调用没走预期逻辑),排查成本高得多。
static、final、private 方法不能被重写
这是初学者最容易混淆的点。这三类方法在语义上不支持运行时动态绑定:
-
static方法属于类,不是实例,调用看的是引用类型(左边),不是实际对象类型 → 行为叫“隐藏”(hiding),不是重写 -
final方法禁止子类修改实现,强行定义同名方法 → 编译报错:cannot override the final method -
private方法对子类不可见,子类里写的同名方法只是新方法,跟父类毫无关系;哪怕加@Override也会编译失败
特别注意:private 方法看似“被覆盖”了,其实只是名字碰巧一样。通过反射或调试能看出它们在字节码里是完全独立的符号。
@Override,用 IDE 的重写生成功能,而不是手敲。







