2011-06-04 109 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?