7

それは大した問題ではありませんが、むしろそれが可能であることに興奮しています! 私がこの小さな例を書いたのは、反対のことを証明するためだけでした。コンパイル エラーか、値のいずれか (111 か 222 か、よくわかりませんでした) が予想されました。

scala> trait T1 { private val v = 111; def getValueT1 = v }
scala> trait T2 { private val v = 222; def getValueT2 = v }
scala> class T12 extends T1 with T2                        
scala> val t = new T12                                     
scala> t.getValueT1                                        
res9: Int = 111
scala> t.getValueT2                                        
res10: Int = 222

vget がオーバーライドされないのはなぜですか? もちろん、これはvs がプライベートである場合にのみ機能しますが、それでも機能します。

4

3 に答える 3

15

トレイトは単なるインターフェースではないため、内部状態を保存する何らかの方法が必要です。しかし、インターフェースと互換性がなければなりません。では、それらは何をするのでしょうか? 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この例では がマングルされていないことに注意してください。)

于 2011-03-05T12:56:48.853 に答える
6

これは特性に固有のプロパティではありません。例えば:

scala> class X {
     |   private val v = 111
     |   def getX = v
     | }
defined class X

scala> class Y extends X {
     |   private val v = 222
     |   def getY = v
     | }
defined class Y

scala> new Y
res0: Y = Y@5ca801b0

scala> res0.getX
res1: Int = 111

scala> res0.getY
res2: Int = 222

Java でも同じことが言えます。Private メンバーはprivateです。それらは、定義された場所にのみ属し、外部では影響を与えません。継承による競合が発生した場合、それらは可視化され、プライベートであるという目的が無効になります。

于 2011-03-05T15:22:21.030 に答える
1

プライベート メンバーとメソッドはオーバーライドできません。子孫によって注入されたクラスの動作の変更を防ぐためです。ここでの概念は C++ の概念と非常に似ています。各祖先は、特別なメソッド (仮想継承など) が呼び出されるまで、独自のメンバーのコピーを保持します。

于 2011-03-05T12:42:25.370 に答える