トレイトは単なるインターフェースではないため、内部状態を保存する何らかの方法が必要です。しかし、インターフェースと互換性がなければなりません。では、それらは何をするのでしょうか? javap -l -s -c -private
これらは、フィールドのように見えるもののアクセサーを作成します (クラス ファイルで (とりわけ) で確認できるように):
public interface T1 extends java.lang.Object {
public abstract int T1$$v();
Signature: ()I
public abstract int getValueT1();
Signature: ()I
}
次に、機能を実装するための静的メソッドを持つ実装クラスを作成します。
public abstract class T1$class extends java.lang.Object {
public static int getValueT1(T1);
Signature: (LT1;)I
Code:
0: aload_0
1: invokeinterface #12, 1; //InterfaceMethod T1.T1$$v:()I
6: ireturn
}
さて、願わくば、これらの内部生成メソッドは method の名前に trait の名前が含まれているため、これらがデフォルトで分離されていることは明らかです。の実装を見ると、次のようになりますT12
。
public class T12 extends java.lang.Object implements T1,T2,scala.ScalaObject {
private final int Overridden$T1$$v;
Signature: I
public final int T1$$v();
Signature: ()I
Code:
0: aload_0
1: getfield #22; //Field T1$$v:I
4: ireturn
public int getValueT1();
Signature: ()I
Code:
0: aload_0
1: invokestatic #29; //Method T1$class.getValueT1:(LT1;)I
4: ireturn
}
特定の特性ごとに必要なものを埋めているだけであることがわかります。問題は、どのようにして特性が相互に上書きされるのかということです。完全に分離しているようです!それがコンパイラの仕事です。何かがある場合、それはprivate
隠され、オーバーライドできないため、別の (プライベートな) ものに同じ名前が付いていても問題ありません。しかし、そうでない場合、コンパイラは衝突について不平を言います:
error: overriding value v in trait T1 of type Int;
value v in trait T2 of type Int needs `override' modifier
class T12 extends T1 with T2
これは、特性名が埋め込まれた秘密のマングル名を使用していないためです。(getValueT1
この例では がマングルされていないことに注意してください。)