抽象方法中的多态和检查异常抛出

时间:2019-06-20 17:14:52

标签: java polymorphism

假设我们有一个类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”

我理解这是因为覆盖方法“可能只抛出其父方法的检查异常以及任何未检查的异常”

为什么会这样呢?为什么我们应该禁止自己抛出更广泛的例外?

(我也在寻找解决方法)

谢谢!

2 个答案:

答案 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进行编程并处理所有声明的检查异常将是不够的。