2011-09-06 9 views
5

私はちょうど私に奇妙ないくつかの状況を偶然見つけました。私は非常によくここに明白な行方不明かもしれない - とにかく、私を助けてください。私はクラス属性「ヴァルS」とクラスXを定義していたスクリプトではScalaコンストラクタの引数は重複していますか?

scala> class X(val s: String) { def run=println("(X): "+s) } 
defined class X 

scala> class Y(s: String) extends X("MY "+s) { override def run=println("(Y): "+s) } 
defined class Y 

scala> new Y("fish").run 
(Y): fish 

は以下のScala REPLスクリプトを考えてみましょう。 次に、1つのコンストラクタ引数をとり、それをXに渡すことになっているクラスYを定義します。違いを表示するには、X( "MY" + s)に渡す前に "s"を修正してください。

最後に新しいYを作成して「実行」を呼び出します。これはコンソールに "fish"を表示するので、明らかに、クラス "X"の属性 "s"は、 "Y"で作成した新しい属性 "s"によって隠されています。

スカラ2.8と2.9.1で同じ結果を試しました。

これはこの方法になっていますか?自分のクラスのコンストラクタ引数をスーパークラスに渡し、そのクラスを子クラスの中に自分自身で格納したくない場合はどうすればよいでしょうか?ここでの一般的な練習は何ですか?

ありがとうございます!

答えて

8

サブクラスのコンストラクタでパラメータexceptを使用しない場合、パラメータは保存されません。コンストラクターパラメーターではなく親パラメーターを参照する必要がある場合は、別の変数名を使用します。例を示す

クラス:

class X(val s: String) { def run=println("(X): "+s) } 
class Y(s: String) extends X("MY "+s) { override def run=println("(Y): "+s) } 
class Z(s0: String) extends X("MY "+s0) { override def run=println("(Z): "+s) } 

バイトコードストレージの欠如を示す(単にコンストラクタ):

// Note putfield to store s 
public X(java.lang.String); 
    Code: 
    0: aload_0 
    1: aload_1 
    2: putfield #11; //Field s:Ljava/lang/String; 
    5: aload_0 
    6: invokespecial #43; //Method java/lang/Object."<init>":()V 
    9: return 

// Note putfield to store new s (then eventually calls X's constructor) 
public Y(java.lang.String); 
    Code: 
    0: aload_0 
    1: aload_1 
    2: putfield #29; //Field s:Ljava/lang/String; 
    5: aload_0 
    6: new #16; //class scala/collection/mutable/StringBuilder 
    9: dup 
    10: invokespecial #19; //Method scala/collection/mutable/StringBuilder."<init>":()V 
    13: ldC#40; //String MY 
    15: invokevirtual #25; //Method scala/collection/mutable/StringBuilder.append:(Ljava/lang/Object;)Lscala/collection/mutable/StringBuilder; 
    18: aload_1 
    19: invokevirtual #25; //Method scala/collection/mutable/StringBuilder.append:(Ljava/lang/Object;)Lscala/collection/mutable/StringBuilder; 
    22: invokevirtual #33; //Method scala/collection/mutable/StringBuilder.toString:()Ljava/lang/String; 
    25: invokespecial #44; //Method X."<init>":(Ljava/lang/String;)V 
    28: return 

// Note - no putfield! 
public Z(java.lang.String); 
    Code: 
    0: aload_0 
    1: new #14; //class scala/collection/mutable/StringBuilder 
    4: dup 
    5: invokespecial #17; //Method scala/collection/mutable/StringBuilder."<init>":()V 
    8: ldC#39; //String MY 
    10: invokevirtual #23; //Method scala/collection/mutable/StringBuilder.append:(Ljava/lang/Object;)Lscala/collection/mutable/StringBuilder; 
    13: aload_1 
    14: invokevirtual #23; //Method scala/collection/mutable/StringBuilder.append:(Ljava/lang/Object;)Lscala/collection/mutable/StringBuilder; 
    17: invokevirtual #32; //Method scala/collection/mutable/StringBuilder.toString:()Ljava/lang/String; 
    20: invokespecial #43; //Method X."<init>":(Ljava/lang/String;)V 
    23: return 
+0

詳細な説明ありがとうございます! –

+0

Yのクラスパラメータsは、Xで定義された値をシャドウします。 – mkneissl

1

確かに、パラメータsは影スーパーパラメータ。重要な点は、クラスパラメータの範囲(すなわち、一次コンストラクタのパラメータ)が、のクラス全体であることである。だから、あなたのY.runメソッドでは、sがY.sを参照するという疑問はありません。

これは、sがフィールドで生きていなければならないことを意味し、Rexがあなたに示したように、それはまさに起こっていることです。主コンストラクタのパラメータについては

、3つの選択肢があります。

  • はvarが=>フィールド、ゲッターを行い、セッター
  • のval =>フィールドを作り、
  • もない場合=>はフィールドを作るをゲッタリング必要な(つまり、メソッドで使用されるパラメータ)ゲッター/セッターはありません
関連する問題