在将具有默认实现的方法添加到特征时,我对后向兼容性感到困惑。像:
以前的版本
trait Foo
新版本
trait Foo {
def verifyConsistency: Option[String] = ??? // provide default implementation
}
Migration Manager将此添加报告为二进制不兼容。这是对的吗?
答案 0 :(得分:13)
是的,这是正确的。
当您定义特征Foo
时,它将在底层创建一个(JVM)接口Foo
和一个(JVM)类Foo$class
,其中所有方法实现都定义为静态方法。相应的java代码看起来像这样(对于Foo
的新定义):
interface Foo {
Option<String> verifyConsistency();
}
class Foo$class {
static Option<String> verifyConsistency(Foo self) {
Predef.???();
}
}
当您将Foo
混合到具体类Bar
中时,JVM级别发生的事情是Bar
扩展了接口Foo
,并且它实现了方法{{1只需将调用转发给verifyConsistency
:
Foo$class
这样做的原因是JVM对象模型不支持多重继承。 traits实现不能简单地放在你可以扩展的类中,因为你只能在JVM上扩展一个类。
这种情况的消除是,每当具体类混合一个特征时,该类为特征的每个成员定义“存根”方法(这些方法简单地转发到实际的实现,这是一个静态方法)。 / p>
一个结果是,如果向特征添加新方法,即使您定义了一个实现,也是不够的:需要重新编译混合特征的具体类(以便添加新方法的存根)班级)。如果你不重新编译这些类,你的程序将无法运行,因为你现在有一个应该具体的类(非抽象)并扩展相应的接口但实际上错过了新方法的实现。
在您的情况下,这意味着具有扩展接口class Bar implements Foo {
Option<String> verifyConsistency() {
return Foo$class.verifyConsistency(this); // simple forwarding
}
}
的具体类,但没有Foo
的任何实现。
因此二进制不兼容。