11.4 继承类
Scala类可以继承Java类,反之亦然。大多数情况下,这应该够用了。之前也讨论过,如果方法接收闭包为参数,重写起来就有些麻烦。异常也是个问题。
Scala没有throws
子句。在Scala里,任意方法都可以抛出异常,无需显式声明成方法签名的一部分。不过,如果在Java里重写这样的方法,试图抛出异常,就会陷入麻烦。看个例子。假设用Scala定义了Bird
:
abstract class Bird {
def fly();
//...
}
还有另一个类Ostrich
:
WorkingWithScriptsAndClasses/Ostrich.scala
class Ostrich extends Bird {
def fly() {
throw new NoFlyException
}
//...
}
其中NoFlyException
定义如下:
WorkingWithScriptsAndClasses/NoFlyException.scala
class NoFlyException extends Exception {}
在上面的代码里,Ostrich
的fly()
抛出异常没有任何问题。不过,如果要在Java里实现一个不能飞的鸟,就会有麻烦,如下所示:
WorkingWithScriptsAndClasses/Penguin.java
//Java code
class Penguin extends Bird {
public void fly() throws NoFlyException {
throw new NoFlyException();
}
//...
}
首先,如果只是抛出异常,Java会报错“unreported exception NoFlyException; must be caught or declared to be thrown.”一旦加上了throws
子句,Java又会报错“fly() in Penguin cannot override fly() in Bird; overridden method does not throw NoFlyException.”
即便Scala很灵活,并不强求一定要指定抛出哪些异常,但是要想在Java里继承这些方法,就要告诉Scala编译器,把这些细节记录在方法签名里。Scala为此提供了一个后门:定义@throws
注解。
虽然Scala支持注解,但它却不提供创建注解的语法。如果想创建自己的注解,就不得不用Java来做。@throws
是已经提供好的注解,用以表示方法抛出的受控异常。这样,对我们来说,要在Java里实现Penguin
,必须在把Bird
改成这样:
WorkingWithScriptsAndClasses/Bird.scala
abstract class Bird {
@throws(classOf[NoFlyException]) def fly();
//...
}
现在,编译上面的代码,Scala编译器会在字节码里为fly()
方法放上必要的签名。经过了这个修改,Java类Penguin
就可以正确编译了。
我们已经看到了,Java和Scala互操作是多么容易。对于一致的构造,感觉就像使用其他Java类一样。我们还学会了如何使用“只在一种语言里支持,在另一种语言里不支持”的构造。Scala的一个关键优势在于,它支持Java的语义,并可以用函数式风格将其进一步扩展。与企业级应用和旧代码打交道时,不必舍弃之前的代码。在应用程序里,可以轻松地把Scala代码和既有的Java代码混合到一起。