【问题标题】:Why is this considered an unhandled exception?为什么这被认为是未处理的异常?
【发布时间】:2016-08-23 13:21:31
【问题描述】:

以下代码由于未处理的异常而无法编译,但在我看来应该没有问题:

class Car {
    public void drive() throws Exception {
        System.out.println("Driving...");
    }
}

public class Sedan extends Car {
    public void drive() {
        System.out.println("Driving Sedan...");
    }
    public static void main(String[] args) {
        Car c = new Sedan();
        c.drive(); //unhandled exception!
    }
}

在调用覆盖方法c.drive()时,编译器不应该很明显,不会抛出已检查的异常吗?为什么仅仅因为引用是 Car 类型而不是 Sedan 类型,我们就必须将 drive 视为仍然抛出检查异常?覆盖方法没有!

【问题讨论】:

  • drive 可以抛出 Exceptionmain 无法处理。
  • 因为c 也可能不是Sedan,而throw 也可能是Exception。由于throwCar 中定义,您需要处理它。
  • Sedan c = new Sedan();
  • 编译器不会特意去查看你是否试图欺骗它。您已将超类声明为抛出 Exception,尽管子类可能不会抛出一个,但仍需要处理它,因为它可以抛出一个。
  • 编译器在很多情况下都可以推断出该信息。但至关重要的是,并非在所有情况下都如此,这会导致一套规则如此复杂,以至于没有人能完全理解它们。我想我们都同意 JLS 已经足够复杂了。 :)

标签: java overriding checked-exceptions


【解决方案1】:

不幸的是,不,这对编译器来说并不明显。

编译器本质上是查看Car c 和对drive 的调用。编译器不知道c 指向的对象的运行时类型。因此,它评估Car.drive() 的方法签名,其中包括throws Exception

为了更清楚,如果在其他方法中 c 被重新分配给仍然抛出此异常的某个 SUV 对象怎么办?在调用drive 方法时,编译器无法知道对象的状态。

【讨论】:

  • 实际上,如果我们有final Car c,类型推断是可能的。但这不会发生,因为该语言是围绕静态类型构建的。
  • @dhke 因为我们也有“有效最终”的概念,所以不需要这样的显式标记。但这会非常令人困惑。
  • @dhke 使用类型推断,您将拥有val c = new Sedan(),然后它会出于明显的原因而工作。如果您将类型显式声明为Car,那么这就是您得到的。
【解决方案2】:

你可以修复它

1.

Sedan c = new Sedan();
c.drive();

2.

Car c = new Sedan();
((Sedan) c).drive();

【讨论】:

    猜你喜欢
    • 2015-06-23
    • 2017-03-30
    • 2013-04-25
    • 2012-02-12
    • 1970-01-01
    • 2015-11-03
    • 2019-10-11
    • 2015-12-20
    • 1970-01-01
    相关资源
    最近更新 更多