添加方法与默认实现到性状时,我很困惑向后兼容性。像:是否添加了一个具有破坏向后兼容性的特性方法?
以前的版本
trait Foo
新版本
trait Foo {
def verifyConsistency: Option[String] = ??? // provide default implementation
}
的Migration Manager这个报告除了作为一个二进制不兼容。那是对的吗?
添加方法与默认实现到性状时,我很困惑向后兼容性。像:是否添加了一个具有破坏向后兼容性的特性方法?
以前的版本
trait Foo
新版本
trait Foo {
def verifyConsistency: Option[String] = ??? // provide default implementation
}
的Migration Manager这个报告除了作为一个二进制不兼容。那是对的吗?
嗯是的,它是正确的。
当您定义特征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
,并通过简单的转发调用Foo$class
实现方法verifyConsistency
:
class Bar implements Foo {
Option<String> verifyConsistency() {
return Foo$class.verifyConsistency(this); // simple forwarding
}
}
为什么做这样的原因是JVM对象模型不支持多重继承。特性实现不能简单地放在你可以扩展的类中,因为你只能在JVM上扩展一个类。
这种情况的影响是,每当一个具体类混合一个特质时,该类为特征的每个成员(这些方法简单地转发给实际实现,这是一种静态方法)定义“存根”方法。
其中一个结果是,如果向特征添加新方法,即使定义了实现,也是不够的:混合特征的具体类需要重新编译(以便添加新方法的存根到班级)。如果您不重新编译这些类,那么程序将无法运行,因为您现在将拥有一个类似于具体(非抽象)的类,并且扩展了相应的接口,但实际上错过了新方法的实现。
在你的情况下,这意味着具有扩展接口Foo
的具体类,但没有verifyConsistency
的任何实现。
因此二进制不兼容。
好的谢谢。我认为整个仪式的特点是你可以添加方法,只要你提供一个默认实现,你不必重新编译所有东西。所以我想我错了:-( –