子类重写父类方法时异常声明须遵循“宽进严出”原则:可减少或细化检查异常,不可增加更宽泛的检查异常;运行时异常不受限;父类未声明检查异常时子类不得新增;此举保障多态调用安全与里氏替换原则。

子类重写父类方法时,异常声明必须遵循“宽进严出”原则:子类方法可以抛出更少或更具体的异常,但不能抛出额外的、更宽泛的检查异常(checked exception)。
父类方法声明了检查异常,子类重写时只能缩小或保持不变
如果父类方法声明 throws IOException,子类重写该方法时:
- 可以不声明任何异常(即不写 throws)
- 可以只声明 IOException 的子类,比如 FileNotFoundException
- 不能声明 Exception、SQLException 等与 IOException 无关或更宽泛的检查异常
- 运行时异常(RuntimeException 及其子类)不受限制,子类可自由添加或删除 throws 声明
父类方法没声明检查异常,子类重写时不能新增检查异常
若父类方法签名是 void doWork()(无 throws),子类重写时:
- 不能写成 void doWork() throws IOException
- 可以抛出任意运行时异常,例如 IllegalArgumentException、NullPointerException
- 这是为了保证多态调用安全:父类引用指向子类对象时,调用方只需按父类契约处理异常
编译器强制校验,违反规则直接报错
Java 编译器会在重写时静态检查 throws 子句。例如:
立即学习“Java免费学习笔记(深入)”;
class Parent {
void method() throws IOException {}
}
class Child extends Parent {
// ❌ 编译错误:Cannot override method() throws SQLException
void method() throws SQLException {}
}
这种设计保障了里氏替换原则(Liskov Substitution Principle)——子类对象能安全替代父类对象,而不会让原有异常处理逻辑失效。
实际建议:优先用运行时异常,减少 throws 约束
为提升 API 灵活性和降低继承干扰,可考虑:
- 将业务上不可恢复的错误建模为 RuntimeException 子类(如自定义 ValidationException)
- 对真正需要调用方显式处理的场景,才使用 checked exception
- 若父类用了 checked exception,子类想简化调用,可在内部捕获并转为运行时异常(需谨慎权衡语义)


















