【问题标题】:SCJP - override method with exception handling raises a compiler errorSCJP - 具有异常处理的覆盖方法引发编译器错误
【发布时间】:2016-12-04 02:38:11
【问题描述】:

在 Kathey Sierra 的 SCJP 书中,摘录如下:


如果一个方法被覆盖但你使用了多态(超类型) 使用覆盖方法引用子类型对象的引用, 编译器假定您正在调用 方法。如果超类型版本声明了一个检查异常,但是 覆盖子类型方法没有,编译器仍然认为你是 调用声明异常的方法(第 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
    }
}

由于在 Animal 上声明了 Exception,此代码将无法编译 吃()方法。即使在运行时,eat() 也会发生这种情况 使用的方法是 Dog 版本,它没有声明 例外。


现在我不明白的是,a.eat(); 怎么会引发编译器错误? (即使 Super 有,child 中的重写函数也可能没有任何异常)

【问题讨论】:

  • 您不接受我的回答有什么具体原因吗?我不介意改变接受,但只是不接受有点奇怪......

标签: java exception overriding scjp


【解决方案1】:

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

  • 狗,那么调用不会抛出异常
  • 一个动物,那么这个调用可能会抛出

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

重写方法并减少 throws 签名非常好。当子类从不抛出时,知道如何处理异常的调用者肯定会工作。

【讨论】:

  • 所以基本上 main() 没有处理 Animal 引用eat() 方法调用可能引发的错误?在编译时,编译器发现此调用可能会引发错误,而此时它实际上并不知道真实对象。我说的对吗?
  • @Tausifmohammad 是的,您对此是正确的。奇怪,我以为昨天已经在这里写了评论。
【解决方案2】:

编译器不知道所引用对象的真实类型。它只检查分配是否有效。

a.eat 的调用会导致编译错误,因为编译器不知道a 引用的Animal 是Dog2。它是根据引用 Dog2 的变量的类型来决定是否可以抛出已检查的异常。

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

正如当您使用其超类的类型引用一个对象时,您不会看到特定于子类的方法,您也会看到超类的 throws 子句,而不是子类的方法。

如果你在最后一行给子类添加一个强制类型转换:

((Dog2)a).eat();

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

【讨论】:

  • 所以编译器只关心a.eat()public void eat() throws Exception 在超类上,甚至不关心子类方法??如果是这样,为什么在没有未报告的异常的情况下提出编译错误? (我很困惑T.T)
  • @peurocs4: 编译器不知道变量引用的对象的真实类型
  • 哦,现在我明白了.. main 函数没有捕获任何异常,但是eat() 函数抛出了异常。这是为什么??
猜你喜欢
  • 1970-01-01
  • 2018-11-06
  • 2017-06-09
  • 1970-01-01
  • 1970-01-01
  • 2018-05-03
  • 2015-07-29
  • 2017-03-16
  • 1970-01-01
相关资源
最近更新 更多