在凯西·塞拉(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类永远不会投掷的呼叫者。