我有两个scala类(当我使用javap -private
读取类文件时,它们的Java代码)。
当我在n
方法中使用d
和toString
时,它会在类中生成私有成员字段。这是为什么?我有点困惑。
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);
}
答案 0 :(得分:7)
嗯,n
和d
的价值需要从toString
机构内部以某种方式提供,对吧?否则你无法使用它们。当您构建新实例并且n
和d
碰巧在堆栈上,以及当您致电toString
,n
和{{1}时,可能会发生任何事情已经很久从堆栈中消失了。因此,编译器会自动将值保存在字段中 - 即使您未在代码中将它们声明为p
。编译器将对在类的构造函数之外使用的所有构造函数变量执行此操作(请记住,类的构造函数实际上是类本身的整个主体,不包括(private) val
和val
定义)。
答案 1 :(得分:3)
Scala将采用构造函数参数,即使未声明val
或var
,也可以将它们作为私有字段添加到类中,如果它们需要在构造函数之外使用的话。
在您的情况下,可以在创建对象后很长时间调用toString
。所以这些参数需要存储在构造的实例中。
答案 2 :(得分: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);
}
不同之处在于,当您在方法中使用d
和n
时,必须保留它们。如果它们没有在方法中使用,只在构造函数中(例如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行?