需要帮助解释scala问题吗

需要帮助解释scala问题吗,scala,Scala,我有两个scala类(以及使用javap-private读取类文件时的Java代码) 当我在toString方法中使用n和d时,它将在类中生成私有成员字段。为什么呢?我有点困惑 Scala#1: javap的等价物: public class com.zjffdu.tutorial.scala.Rational extends java.lang.Object implements scala.ScalaObject{ public com.zjffdu.tutorial.scala.R

我有两个scala类(以及使用
javap-private
读取类文件时的Java代码)

当我在
toString
方法中使用
n
d
时,它将在类中生成私有成员字段。为什么呢?我有点困惑

Scala#1:

javap的等价物:

public class com.zjffdu.tutorial.scala.Rational
extends java.lang.Object
implements scala.ScalaObject{
    public com.zjffdu.tutorial.scala.Rational(int, int);
}
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);
}
Scala#2:

javap的等价物:

public class com.zjffdu.tutorial.scala.Rational
extends java.lang.Object
implements scala.ScalaObject{
    public com.zjffdu.tutorial.scala.Rational(int, int);
}
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);
}

嗯,
n
d
的值需要从
toString
主体内部以某种方式提供,对吗?否则你就无法使用它们。当您构造一个新实例时,
n
d
恰好在堆栈上,当您调用
toString
时,
n
p
早已从堆栈中消失,这两者之间可能发生任何事情。因此,编译器会自动将值保存在字段中,即使在代码中没有将它们声明为
(private)val
s。编译器将对类的构造函数之外使用的所有构造函数变量执行此操作(请记住,类的构造函数实际上是类本身的整体,不包括
val
def
定义)。

Scala将采用构造函数参数,即使未声明
val
var
,如果需要在构造函数之外使用它们,也可以将它们作为私有字段添加到类中


在您的情况下,
toString
可以在对象创建后很久调用。因此,这些参数需要存储在构造的实例中。

好吧,这里更有趣。如果您尝试以下方法:

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
initialization),则它们不需要作为每个实例的成员存在。查看
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
public java.lang.String toString();
代码:
0:新的#10//类scala/collection/mutable/StringBuilder
3:dup
4:特别是#14//方法scala/collection/mutable/StringBuilder。“”:()V
7:aload_0
8:getfield#19//田纳西州:我
11:invokevirtual#23//方法scala/collection/mutable/StringBuilder.append:(I)Lscala/collection/mutable/StringB
造船厂;
14:最不发达国家25//串/
16:invokevirtual#28//方法scala/collection/mutable/StringBuilder.append:(Ljava/lang/Object;)Lscala/collectio
n/mutable/StringBuilder;
19:aload_0
20:getfield#30//d场:我
23:invokestatic#36//方法scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;
26:invokevirtual#28//方法scala/collection/mutable/StringBuilder.append:(Ljava/lang/Object;)Lscala/collectio
n/mutable/StringBuilder;
29:invokevirtual#38//方法scala/collection/mutable/StringBuilder.toString:()Ljava/lang/String;
32:轮到你了

参见第8行和第20行?

如果是
val-toString
而不是
def-toString
,会发生同样的事情吗?如果是
val-toString
,那么你会看到一个
toString
字段。是的,当然,但是n和d的私有字段应该是正确的?soc-确实,您将看到
toString
而不是
n
d
,而不是它们。