まあまあ正しいです。もし形質Foo
を定義するとき
、それはフードの下(JVM)インターフェースFoo
及び静的メソッドとして定義されているすべてのメソッドの実装と(JVM)クラスFoo$class
の両方を作成します。 、あなたは具体的なクラスBar
にFoo
を混ぜるとき
interface Foo {
Option<String> verifyConsistency();
}
class Foo$class {
static Option<String> verifyConsistency(Foo self) {
Predef.???();
}
}
は、JVMレベルで何が起こるかBar
インターフェイスFoo
を拡張することです:対応するJavaコードは(Foo
の新しいdefintionのため)このようなもののようになります。そして、それは単にFoo$class
にコールを転送することによって方法verifyConsistency
を実装しています
class Bar implements Foo {
Option<String> verifyConsistency() {
return Foo$class.verifyConsistency(this); // simple forwarding
}
}
それがこのように行われている理由は、JVMのオブジェクトモデルが多重継承をサポートしていないということです。 JVM上で単一のクラスを拡張することができるだけであるため、特性実装は、拡張するクラスに単純に配置することはできません。
具体的なクラスが特性を混合するたびに、クラスは特性の各メンバー(静的メソッドである実際の実装に単純に転送するメソッド)に「スタブ」メソッドを定義します。
結果として、新しいメソッドを特性に追加すると、実装を定義しても、特性を混合する具体的なクラスが再コンパイルする必要があります(新しいメソッドのスタブが追加されるクラスに)。これらのクラスを再コンパイルしないと、具体的な(抽象的ではない)クラスが作成され、対応するインタフェースが拡張されますが、実際には新しいメソッドの実装が見付かりません。
これは、インターフェイスFoo
を拡張する具体的なクラスを持つことを意味しますが、verifyConsistency
の実装はありません。
したがって、バイナリの非互換性。
ありがとうございました。私は、特性を取り巻く全体的な儀式は、メソッドを追加できると思っていました。あなたがデフォルトの実装を提供する限り、すべてを再コンパイルする必要はありません。だから私はそこに間違っていたと思う:-( –