子类重写方法抛出的检查型异常不能比父类更宽泛,只能是父类声明异常的子类或不抛出;运行时异常不受限制,多态调用按父类throws声明捕获。

Java 中多态下的方法重写,对异常抛出有明确且严格的规范——它直接关系到编译能否通过,也影响运行时多态的正确性。核心原则就一条:子类重写方法抛出的检查型异常(checked exception)不能比父类方法更宽泛,只能相同或更具体。
异常类型必须遵循继承关系
子类重写方法声明 throws 的检查型异常,只能是父类对应方法所声明异常的子类,或者不抛出任何检查型异常。比如父类方法 throws IOException,子类可以 throws FileNotFoundException(它是 IOException 的子类),也可以不写 throws;但绝不能 throws Exception 或 SQLException(它们与 IOException 无继承关系,或范围更宽)。
- ✅ 允许:父类 throws IOException → 子类 throws FileNotFoundException
- ✅ 允许:父类 throws IOException → 子类不 throws 任何 checked 异常
- ❌ 禁止:父类 throws IOException → 子类 throws Exception
- ❌ 禁止:父类 throws IOException → 子类 throws SQLException
运行时异常不受限制
RuntimeException 及其子类(如 NullPointerException、ArrayIndexOutOfBoundsException)属于非检查型异常,重写时无需在 throws 中声明,也不受上述规则约束。子类可自由抛出、不抛出,或抛出不同类型的运行时异常,编译器不检查,多态调用也不会出错。
- 父类方法 throws IOException,内部还 throw new IllegalArgumentException() —— 合法
- 子类重写时 throw new NumberFormatException() —— 合法,无需声明,也不影响多态
多态调用时的异常捕获要按父类声明来
当用父类引用指向子类对象(如 Animal a = new Dog()),调用重写方法时,编译器只认父类方法签名中的 throws 声明。也就是说,try-catch 必须能捕获父类声明的异常类型(或其父类),否则编译失败。即使子类实际抛出的是更具体的异常(如 FileNotFoundException),catch 块仍需按父类声明的 IOException 来写。
立即学习“Java免费学习笔记(深入)”;
- Animal a = new Dog(); try { a.eat(); } catch (IOException e) { ... } —— 正确,因编译期看 Animal.eat()
- 不能写 catch (FileNotFoundException e),因为编译器不知道子类会抛这个
- 但可以写 catch (Exception e),因 Exception 是 IOException 的父类
private、static、final 方法不参与多态,也不涉及该规范
这些方法无法被重写,自然不存在“重写时异常怎么抛”的问题。private 方法子类不可见;static 方法属于类,调用由引用类型决定(编译时绑定);final 方法禁止重写。它们的异常声明各自独立,互不影响多态行为。
- 父类 static void load() throws Exception,子类写 static void load() throws RuntimeException —— 这不是重写,是隐藏,彼此无关
- 子类重写普通实例方法时,才需要严格遵守 throws 的继承约束


















