Ovrerriding方法和处理异常

时间:2015-12-30 17:29:23

标签: java

我知道Liskov替代原则。

但我仍然对以下代码有疑问:

下面的代码有父类A和子类B. {B}子类中重写了testException方法,因此它不会抛出任何已检查的异常。

public class A {
    public void testException() throws IOException{
        //some code with IO  
    }
}

public class B extends A {
    public void testException() {
        //no IO code
    }
}

public class Test {

    public static void main(String[] args) {
        first:
        try {// compilation error
            B b = new B();
            b.testException();
        } catch (IOException e) {}

        second:
        try {
            A a = new B();// Why does not cause compilation error?
            a.testException();
        } catch (IOException e) {}

    }

}                 

在Test类中,标记为first的try-catch块不会编译。但第二块没有任何问题。那是为什么?

更新:我认为第二个块只是因为运行时多态性而编译,类型A的对象a可以在运行时指向任何子类,编译器也不会对它有任何线索,对吧?

3 个答案:

答案 0 :(得分:1)

您的错误来自于B类中的testException方法不会引发IO异常,因此您的try / catch块中不会捕获可能的异常。

答案 1 :(得分:1)

  

我认为第二个块只是因为运行时多态性而编译,A类型的对象在运行时可以指向任何子类,而编译器也不会对它有任何线索,对吧?

是的,就是这样。在first块中,我们确定b

B b = ...
b.testException();

的类型为B,这意味着它可以包含类B或其子类的实例。由于编译器知道类testException()(或其子类)中的B方法永远不会抛出任何IOException(子类不能向重写方法添加新的已检查异常),因此它会通知您试图做一些不必要的事情(创建死代码 - 永远不会被执行的代码),在这种情况下处理异常,这里没有机会抛出。

这种情况在second阻止的情况下有所不同,因为我们有

A a = ....
a.testException();

此处编译器无法确定a将保留哪个对象(至少在其当前版本中不会,可能在将来此行为将得到改进)。因此虽然它可能包含类B的实例,但它也可能是类A的实例。因此,testException可能会抛出IOException,并且编译器没有任何理由阻止您处理它(由于这种可能性,实际上处理它是强制性的。)

答案 2 :(得分:0)

 A a = new B();
 a.testException();

编译器将在此处请求try-catch块或throws子句,因为多态性是运行时现象,编译器在编译时解析方法调用。

因此,它看到testException()中的A会引发IOException因此请求try-catch阻止或throws条款。