6

throws在 Java 中,如果原始抽象方法没有( .) ,则无法指定被覆盖的抽象方法某个异常( overridden method does not throw Exception。)但是在 Scala 中,您可以这样做,因为它没有检查的异常。很好,但是如果您使用@throws应该提示 Java 编译器了解正在发生的事情的注释,对吗?

鉴于此 Scala 代码:

package myscala

abstract class SFoo {
    def bar(): Unit
}

class SFoobar extends SFoo {
    @throws[Exception]
    override def bar(): Unit = {
        throw new Exception("hi there")
    }
}

我有两个不同的 Java 程序,其中一个将编译并Exception在运行时运行,另一个不会编译。

编译:

import myscala.SFoo;
import myscala.SFoobar;

public class Foobar {
    public static void main(String[] args) {
        SFoo mySFoo = new SFoobar();
        mySFoo.bar();
    }
}

不编译 ( unreported exception Exception; must be caught or declared to be thrown):

import myscala.SFoo;
import myscala.SFoobar;

public class Foobar {
    public static void main(String[] args) {
        SFoobar mySFoo = new SFoobar();       // only difference is the declared type
        mySFoo.bar();
    }
}

我真的不明白。SFoobar.bar为什么即使Foo.bar没有这样的声明,Java 编译器也没有注意到我声明会引发异常的事实,并因此引发类似的编译错误?

4

1 回答 1

7

如果将 Scala 代码转换为等效SFooSFooBarJava 代码:

abstract class SFoo {
    void bar() {}
}

class SFoobar extends SFoo {
    void bar() throws Exception {
        throw new Exception("hi there");
    }
}

它不会编译,因为:

error: bar() in SFoobar cannot override bar() in SFoo
        void bar() throws Exception {
             ^
  overridden method does not throw Exception

Java 强制执行规则,即覆盖方法不能抛出它们所覆盖的方法没有抛出的异常。这使得检查异常在向上转换时是类型安全的,例如在将 a 转换SFooBarSFoo.

您对类的第一个定义 FooBar,其中 anSFooBar存储在SFoo变量中,如果SFoo并且SFooBar已经在 J​​ava 中定义,那将是完全安全的。Java 编译器知道 anSFoo.bar不会 throw Exception,并假定已遵守重写方法的规则,因此这里不做任何额外检查。

然而,Scala 编译器并不关心重写方法的这条规则,并且允许你破坏这种类型安全。Java 编译器忽略了这一事实,因此生成了在运行时中断的代码。这是 Java 和 Scala 之间的不匹配,这两个编译器都无法解决。

于 2014-08-05T04:17:39.377 回答