2011-06-04 410 views
4

我有兩個scala類(以及他們的Java代碼,當我使用javap -private來讀取類文件時)。需要幫助來解釋scala問題

當我在toString方法中使用nd時,它將在類中生成私有成員字段。這是爲什麼?我有點困惑。

Scala的#1:

class Rational(n: Int, d: Int) { 

} 

等效從javap的:

public class com.zjffdu.tutorial.scala.Rational 
extends java.lang.Object 
implements scala.ScalaObject{ 
    public com.zjffdu.tutorial.scala.Rational(int, int); 
} 

Scala的#2:

class Rational(n: Int, d: Int) { 
    override def toString() = n + "/" + d 
} 

從javap的當量:

public class com.zjffdu.tutorial.scala.Rational 
extends java.lang.Object 
implements scala.ScalaObject{ 
    private final int n; 
    private final int d; 
    public java.lang.String toString(); 
    public com.zjffdu.tutorial.scala.Rational(int, int); 
} 

回答

7

那麼,nd的值需要從toString體內以某種方式獲得,對吧?否則,你不能使用它們。當你構建一個新的實例和nd恰好在堆棧上,並且當你調用toString,n和很早就從堆棧中消失之間可能發生任何事情。因此,編譯器會自動將值保存在字段中 - 即使您未在代碼中將它們聲明爲(private) val。編譯器會爲所有在類的構造函數之外使用的構造函數變量這樣做(請記住,類的構造函數實際上是類本身的整體,不包括valdef定義)。

3

即使沒有聲明valvar,Scala也會使用構造函數參數,並將它們作爲私有字段添加到類中,前提是它們需要在構造函數之外使用。

在你的情況下,toString可能會在對象創建後調用很長時間。所以這些參數需要存儲在構造的實例中。

+0

當val toString而不是'def toString'時會發生同樣的事情嗎? – soc 2011-06-04 14:07:30

+0

如果它是'val toString',那麼你會看到'toString'字段。 – 2011-06-04 14:15:43

+0

是的,當然,但那麼n和d的私人領域應該是正確的? – soc 2011-06-04 14:44:56

2

好吧,這裏更有趣。如果你嘗試這樣做:

class Rational(n: Int, d: Int) { 
    override val toString = n + "/" + d 
} 

然後私人汽車瓦爾消失了!

public class Rational extends java.lang.Object implements scala.ScalaObject{ 
    private final java.lang.String toString; 
    public java.lang.String toString(); 
    public Rational(int, int); 
} 

不同的是,當你在一個方法使用dn,他們必須被保留。如果它們不在方法中使用,只在構造函數中使用(例如val初始化),則它們不需要作爲每個實例的成員存在。看看的def toString經反編譯的版本:

public java.lang.String toString(); 
    Code: 
    0: new  #10; //class scala/collection/mutable/StringBuilder 
    3: dup 
    4: invokespecial #14; //Method scala/collection/mutable/StringBuilder."<init>":()V 
    7: aload_0 
    8: getfield  #19; //Field n:I 
    11: invokevirtual #23; //Method scala/collection/mutable/StringBuilder.append:(I)Lscala/collection/mutable/StringB 
uilder; 
    14: ldc  #25; //String/
    16: invokevirtual #28; //Method scala/collection/mutable/StringBuilder.append:(Ljava/lang/Object;)Lscala/collectio 
n/mutable/StringBuilder; 
    19: aload_0 
    20: getfield  #30; //Field d:I 
    23: invokestatic #36; //Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer; 
    26: invokevirtual #28; //Method scala/collection/mutable/StringBuilder.append:(Ljava/lang/Object;)Lscala/collectio 
n/mutable/StringBuilder; 
    29: invokevirtual #38; //Method scala/collection/mutable/StringBuilder.toString:()Ljava/lang/String; 
    32: areturn 

見8號線和20?