开发者

Need help for explain scala problem

I have two scala classes (and their Java code when I use javap -private to read the class file).

When I use n and d in the toString method, it will generate private member field in class. Why is that? I'm a little confused.

Scala #1:

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

}

equivalent from 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 de开发者_如何学编程f toString() = n + "/" + d
}

equivalent from 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);
}


Well, the value of n and d needs to be available somehow from inside the toString body, right? Otherwise you couldn't use them. Anything could happen between when you construct a new instance and n and d happen to be on the stack, and when you call toString, and n and p have long disappeared from the stack. So the compiler automatically saves the value in fields — even if you don't declare them as (private) vals in your code. The compiler will do so for all constructor variables that are used outside of the constructor of your classes (remember that the constructor of a class is actually the whole body of the class itself, excluding val and def definitions).


Scala will take constructor arguments, even if not declared val or var and add them as private fields to a class if they ever need to be used outside of the constructor.

In your case, toString could be called long after object creation. So those parameters need to be stored in the constructed instance.


Well, here's more even fun. If you try this:

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

Then the private vars disappear again!

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);
}

The difference is that when you use d and n in a method, they have to be preserved. If they are not used in a method, only in the constructor (such as val initialization), then they don't need to exist as members of each instance. Take a look at the decompiled version of 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

See lines 8 and 20?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜