SCJP-具有异常处理的覆盖方法会引起编译器误差



在凯西·塞拉(Kathey Sierra)的SCJP书中,摘录如下:


如果方法被覆盖,但使用多态性(超图) 参考使用覆盖方法参考子类型对象, 编译器假设您正在调用supertype版本 方法。如果Supertype版本声明了检查的例外,但是 覆盖亚型方法没有,编译器仍然认为您是 调用一种声明例外的方法(更多在第5章中)。

让我们看一个例子:

class Animal {
    public void eat() throws Exception {
        // throws an Exception
    }
}
class Dog2 extends Animal {
    public void eat() { /* no Exceptions */ }
    public static void main(String[] args) {
        Animal a = new Dog2();
        Dog2 d = new Dog2();
        d.eat();   // ok
        a.eat();   // compiler error - 
                   // unreported exception
    }
}

由于在动物上声明的例外,此代码不会编译 Eat()方法。即使在运行时,这种情况也会发生() 使用的方法将是狗版本,该版本不声明 例外。


现在我不明白的是a.eat();如何增加编译器错误?(即使超级效果,儿童的覆盖功能也可能没有任何例外)

编译器不知道引用对象的实际类型。它仅检查作业是否有效。

呼叫a.eat会导致编译错误,因为编译器不知道A IS DOG2所引用的动物。它决定是否仅根据引用dog2的变量的类型来抛出检查的例外。

编译器并不聪明。它不运行代码,也不会跟踪分配给变量a的对象的实际类。

就像您参考具有其超类类型的对象时,您不会看到特定于子类的方法一样,您还可以看到超级类的throws子句,而不是子类方法的throws子句。

如果您在最后一行中添加了子类:

((Dog2)a).eat();

那么您将不会得到未报告的异常编译错误。

当您查看代码时,您可以意识到:当您调用()的对象是

  • 一只狗,然后电话不会引发异常
  • 动物,然后那个电话可以扔

因此,第二次用法导致编译器向您抱怨。

覆盖一种方法,降低 throw签名是完全可以的。一个知道如何处理Sub类永远不会投掷的呼叫者。

最新更新