为什么重写方法不能引发比重写方法更广泛的异常?

2022-08-31 09:21:21

我正在阅读Kathe sierra的SCJP 6书,并遇到了这种以覆盖方法抛出异常的解释。我完全不明白。任何人都可以向我解释一下吗?

重写方法不得引发新的或比重写方法声明的异常更广泛的已检查异常。例如,声明 FileNotFoundException 的方法不能被声明 SQLException、Exception 或任何其他非运行时异常的方法重写,除非它是 FileNotFoundException 的子类。


答案 1

这意味着,如果一个方法声明抛出一个给定的异常,那么子类中的重写方法只能声明抛出该异常或其子类。例如:

class A {
   public void foo() throws IOException {..}
}

class B extends A {
   @Override
   public void foo() throws SocketException {..} // allowed

   @Override
   public void foo() throws SQLException {..} // NOT allowed
}

SocketException extends IOException,但不会。SQLException

这是因为多态性:

A a = new B();
try {
    a.foo();
} catch (IOException ex) {
    // forced to catch this by the compiler
}

如果决定抛出 ,那么编译器不能强迫你抓住它,因为你引用的是它的超类的实例 - 。另一方面,任何子类都将由处理BSQLExceptionBAIOExceptionIOException

您需要能够通过其超类引用对象的规则是Liskov替换原理。

由于未经检查的异常可以在任何地方抛出,因此它们不受此规则的约束。如果需要,可以将未经检查的异常作为文档形式添加到 throws 子句中,但编译器不会强制执行任何有关它的内容。


答案 2

重写方法可以引发任何未经检查的(运行时)异常,而不管重写的方法是否声明异常

例:

class Super {
    public void test() {
        System.out.println("Super.test()");
    }
}

class Sub extends Super {
    @Override
    public void test() throws IndexOutOfBoundsException {
        // Method can throw any Unchecked Exception
        System.out.println("Sub.test()");
    }
}

class Sub2 extends Sub {
    @Override
    public void test() throws ArrayIndexOutOfBoundsException {
        // Any Unchecked Exception
        System.out.println("Sub2.test()");
    }
}

class Sub3 extends Sub2 {
    @Override
    public void test() {
        // Any Unchecked Exception or no exception
        System.out.println("Sub3.test()");
    }
}

class Sub4 extends Sub2 {
    @Override
    public void test() throws AssertionError {
        // Unchecked Exception IS-A RuntimeException or IS-A Error
        System.out.println("Sub4.test()");
    }
}

推荐