重写方法必须具有相同的方法签名:方法名、参数列表(类型、数量、顺序)完全一致;返回类型支持协变(子类返回类型为父类返回类型的子类型),但基本类型和void不支持;访问修饰符不能更严格;不能重写final、static、private方法;检查异常声明只能缩小或不变。

重写方法必须有相同的方法签名
Java 要求子类中重写的方法与父类被重写方法的 方法名、参数列表(类型、数量、顺序) 完全一致,否则就是重载或编译错误。返回类型可以是协变的(即子类返回类型是父类返回类型的子类型),但基本类型和 void 不支持协变。
常见错误:
- 不小心改了参数类型(比如把
int写成Integer)——这属于重载,不是重写,@Override注解会报错 - 加了默认参数(Java 不支持默认参数)——直接编译失败
- 泛型擦除后签名冲突,例如父类方法是
,子类写成List getData() List是合法协变;但若写成getData() ArrayList,则因返回类型非父子关系而编译失败getData()
访问修饰符不能更严格,但可以更宽松
子类重写方法的访问级别必须 ≥ 父类方法的访问级别。也就是说:
- 父类是
protected,子类可以是protected或public,但不能是private或包私有(不加修饰符) - 父类是
public,子类也必须是public - 父类是包私有(无修饰符),子类不能是
private,但可以是包私有或更开放的修饰符
违反时编译器直接报错:Cannot reduce the visibility of the inherited method
立即学习“Java免费学习笔记(深入)”;
不能重写 final、static、private 方法
这是三个典型“不可覆盖”场景,原因各不相同:
-
final方法:语义上禁止子类修改行为,编译器强制拦截 -
static方法:属于类而非实例,调用依赖编译时类型,实际是“隐藏(hiding)”而非“重写”,即便加@Override也会编译失败 -
private方法:对子类不可见,子类里同名方法只是新定义,跟父类无关;加@Override会触发编译错误method does not override or implement a method from a supertype
注意:private 方法虽不可重写,但它可能被父类其他 public/protected 方法调用——这种设计常用于模板方法模式中的钩子,但子类无法干预其执行逻辑。
异常声明只能缩小或不变,不能扩大
子类重写方法抛出的检查异常(checked exception)必须是父类方法所声明异常的子集或完全不抛出;运行时异常(unchecked)不受此限。
示例:
class Parent {
void doWork() throws IOException { ... }
}
class Child extends Parent {
@Override
void doWork() throws FileNotFoundException { ... } // ✅ 合法:FileNotFoundException 是 IOException 子类
@Override
void doWork() throws Exception { ... } // ❌ 编译错误:Exception 范围更大
@Override
void doWork() throws RuntimeException { ... } // ✅ 合法:RuntimeException 是 unchecked
@Override
void doWork() { ... } // ✅ 合法:不抛任何 checked 异常
}
容易忽略的是:如果父类方法没声明任何 checked 异常,子类重写方法就完全不能声明 checked 异常——哪怕只加一个 throws SQLException 都会编译失败。
最易踩的坑往往不在语法层面,而在语义一致性:比如重写了 equals() 却忘了同步更新 hashCode(),或重写 clone() 未调用 super.clone() 导致字段复制不完整。这些不违反重写规则,却破坏对象契约。










