使用构造函数params在scala中扩展一个类会在类中添加vals(字段)吗?

时间:2010-09-10 13:53:49

标签: inheritance scala

说我有:

class A(val foo: String)

class B(foo: String) extends A(foo)
class C(val foo: String) extends A(foo)
class D(override val foo: String) extends A(foo)
class E(bar: String) extends A(bar)

我对每个类的内存实例占用多少感兴趣。 A类实例将只有一个成员变量:foo。

班级B,C,D和E怎么样?他们各有几个成员变量?我怀疑E会有两个(E.bar,A.foo),我希望D会有一个(A.foo),但我想知道B和C,他们可能有两个吗? (B.foo,A.foo)?

2 个答案:

答案 0 :(得分:14)

所有编译的示例(ABDE)都占用了相同数量的存储空间。事实上,甚至

class F(val bar: String) extends A(bar)

将数据存储在一个字段中 - 它只是为同一个字段获取一个额外的存取方法。但是,如果你

class G(var bar: String) extends A(bar)

然后构建一个新字段。

您可以通过编译上面的示例并查看javap -c Classname中的字节码来检查所有这些(请注意2:构造函数中A处的putfield:

public class Sizes$A extends java.lang.Object implements scala.ScalaObject{
public java.lang.String foo();
  Code:
   0:   aload_0
   1:   getfield    #11; //Field foo:Ljava/lang/String;
   4:   areturn

public Sizes$A(java.lang.String);
  Code:
   0:   aload_0
   1:   aload_1
   2:   putfield    #11; //Field foo:Ljava/lang/String;
   5:   aload_0
   6:   invokespecial   #18; //Method java/lang/Object."<init>":()V
   9:   return    
}

F中没有额外的putfield ......)

public Sizes$F(java.lang.String);
  Code:
   0:   aload_0
   1:   aload_1
   2:   invokespecial   #15; //Method Sizes$A."<init>":(Ljava/lang/String;)V
   5:   return

G中再次存在一个......)

public Sizes$G(java.lang.String);
  Code:
   0:   aload_0
   1:   aload_1
   2:   putfield    #11; //Field bar:Ljava/lang/String;
   5:   aload_0
   6:   aload_1
   7:   invokespecial   #18; //Method Sizes$A."<init>":(Ljava/lang/String;)V
   10:  return

答案 1 :(得分:7)

您的课程C需要override上的val foo关键字进行编译,使其与D相同。它将存储自己的foo副本。您的类B不会添加存储,除非在其构造函数体之外的某个位置存在对foo的引用。这将强制创建隐藏字段以保存构造函数参数。构造函数体是类定义中的所有代码,位于任何方法体之外。

附录:

package storage

    class A(val foo: String)

    class B(             foo: String) extends A(foo)
//  class C(         val foo: String) extends A(foo)
    class D(override val foo: String) extends A(foo)
    class E(             bar: String) extends A(bar)
    class F(             bar: String) extends A(bar) { def barbar: String = bar }

我为此感到困惑:

% javap -private storage.F
Compiled from "Storage.scala"
public class storage.F extends storage.A implements scala.ScalaObject{
    public java.lang.String barbar();
    public storage.F(java.lang.String);
}

方法barbar用什么来获取其返回值?