假设我们有一个类Foo
,它的一个方法可能抛出IOException
。
public abstract class Foo {
public abstract void foo() throws IOException;
}
但是,当我将类扩展为FooImpl
时,
public class FooImpl extends Foo {
public void foo() throws Exception {
throw new Exception("This cannot throw!");
}
}
这将导致编译时错误:“被覆盖的方法不会引发java.lang.Exception”
我理解这是因为覆盖方法“可能只抛出其父方法的检查异常以及任何未检查的异常”
为什么会这样呢?为什么我们应该禁止自己抛出更广泛的例外?
(我也在寻找解决方法)
谢谢!
答案 0 :(得分:4)
您必须始终能够在使用其超类的任何地方使用该子类。从字面上看,这几乎就是子类的定义,并且通常被称为Liskov substitution principle。
因此,鉴于Foo
的定义,以下必须起作用:
Foo foo = getFooFromSomewhere();
try {
foo.foo();
} catch (IOException e) {
// handle e
}
...因为与Foo
的定义匹配。
对于FooImpl
的定义,将不有效,因为不处理非Exception
的{{1}},并且必须将它们作为检查异常被抓或以其他方式处理。
答案 1 :(得分:0)
这是因为超类建立了合同。换句话说,当编译器“验证”重写的方法时,它保证可以使用子类的实例针对超类型的API进行编程。
实际上,如果有的话
Foo foo = some foo implementation;
try {
foo.foo();
} catch(IOException ioe) {
//handle IOException
}
此catch
块应足以处理Foo
API的已检查异常。但是,如果编译器让子类引发超类声明的异常以外的其他检查异常,例如Exception
,则针对Foo
进行编程并处理所有声明的检查异常将是不够的。