子类重写方法Throws限制
在 Java 中,子类重写(override)方法时,对 throws 子句(异常声明)是有明确限制的。核心原则可以概括为一句话:
子类重写的方法,不能抛出比父类方法声明更“宽泛”的受检异常(checked exception)。
下面分情况说明。
一、基本规则(重点)
✅ 允许的情况
子类重写方法:
- 不抛出任何异常
- 只抛出父类方法声明的受检异常
- 抛出父类方法声明的异常的子类异常
- 抛出任意非受检异常(RuntimeException / Error)
❌ 不允许的情况
子类重写方法:
- 抛出父类方法没有声明的受检异常
- 抛出父类方法声明异常的父类异常
二、示例说明
1️⃣ 父类方法声明异常
class Parent {
public void test() throws IOException {
// ...
}
}
✅ 子类合法重写
class Child extends Parent {
@Override
public void test() throws IOException { // 相同异常 ✅
// ...
}
}
class Child extends Parent {
@Override
public void test() { // 不抛异常 ✅
// ...
}
}
class Child extends Parent {
@Override
public void test() throws FileNotFoundException { // 更具体的异常 ✅
// ...
}
}
❌ 子类非法重写
class Child extends Parent {
@Override
public void test() throws Exception { // ❌ Exception 是 IOException 的父类
// ...
}
}
class Child extends Parent {
@Override
public void test() throws SQLException { // ❌ 父类未声明的受检异常
// ...
}
}
三、非受检异常(RuntimeException / Error)不受限制 ✅
class Parent {
public void test() throws IOException {
// ...
}
}
class Child extends Parent {
@Override
public void test() throws IOException, NullPointerException {
// ✅ NullPointerException 是 RuntimeException,不受限制
}
}
原因:
RuntimeException和Error不需要在编译期被捕获或声明,因此不受重写限制。
四、接口方法的特殊情况
接口方法默认是 public abstract,可以声明受检异常。
interface MyInterface {
void doSomething() throws IOException;
}
实现类必须遵守同样的规则:
class Impl implements MyInterface {
@Override
public void doSomething() throws FileNotFoundException {
// ✅
}
}
五、总结口诀(面试常用)
重写方法:
✅ 可以抛更少
✅ 可以抛更具体
❌ 不能抛更宽
✅ RuntimeException 随便抛
如果你愿意,我可以帮你画一张 父类 / 子类异常关系对照图,或者结合 面试题 / 编译错误示例 讲得更深入。