添加方法與默認實現到性狀時,我很困惑向後兼容性。像:是否添加了一個具有破壞向後兼容性的特性方法?
以前的版本
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
的任何實現。
因此二進制不兼容。
好的謝謝。我認爲整個儀式的特點是你可以添加方法,只要你提供一個默認實現,你不必重新編譯所有東西。所以我想我錯了:-( –