2011-09-06 70 views
5

我只是偶然發現了一些對我來說很奇怪的情況。無論如何,我可能很想念這個明顯的問題,請幫助我。斯卡拉構造函數參數是否重複?

考慮下面的斯卡拉REPL腳本:

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 

在腳本中,我定義一個類屬性「VAL的」一類X。 然後我定義了一個類Y,它應該接受一個構造函數參數並將它傳遞給它所做的X-。爲了顯示不同之處,我修改了「s」,然後將其賦予X(「我的」+ s)。

最後我創建一個新的Y並調用「run」。這將「fish」打印到控制檯,因此顯然類「X」的屬性「s」已被我在「Y」中創建的新屬性「s」遮蔽。

我試過這與Scala 2.8和2.9.1具有相同的結果。

這應該是這樣嗎?如果我只想將構造函數參數從我的類傳遞到超類,而不想將自己存儲在子類中,該怎麼辦?這裏常見的做法是什麼?

謝謝!

回答

8

如果除了在子類的構造函數中使用參數,參數將不會被存儲。如果您需要引用父參數而不是構造函數參數,請使用不同的變量名稱。

類表示的例子:

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中的類參數隱藏了X中定義的val。 – mkneissl

1

實際上,參數s陰影超類參數。重要的一點是,類參數的範圍(即主構造函數的參數)是整個類的。所以,在你的Y.run方法中,s不會引用Y.s.

這意味着s必須在一個領域保持活力,正如Rex向您展示的那樣,這正是發生的。

對於主構造符參數,有三個選擇:

  • VAR =>使得場,吸氣劑,和setter
  • VAL =>使得字段和getter
  • 既不=>使得場如果必要的(即方法中使用的參數),但沒有吸氣器/設置器