Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Inheritance 使用构造函数参数扩展scala中的类是否会向该类添加VAL(字段)?_Inheritance_Scala - Fatal编程技术网

Inheritance 使用构造函数参数扩展scala中的类是否会向该类添加VAL(字段)?

Inheritance 使用构造函数参数扩展scala中的类是否会向该类添加VAL(字段)?,inheritance,scala,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) 我感兴趣的是每个类的实例占用多少内存。类的实例将有一个成员变量:foo B、C、D和E班怎么样?它们每个都有多少

假设我有:

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)
我感兴趣的是每个类的实例占用多少内存。类的实例将有一个成员变量:foo


B、C、D和E班怎么样?它们每个都有多少个成员变量?我怀疑E会有两个(E.bar,A.foo),我希望D会有一个(A.foo),但我想知道B和C,他们会有两个吗?(B.foo,A.foo)?

您的类
C
需要在
val foo
上使用
override
关键字进行编译,使其与
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使用什么方法来获取其返回值?

所有编译的示例(
A
B
D
E
)占用的存储空间量完全相同。事实上,甚至

class F(val bar: String) extends A(bar)
将数据存储在一个字段中——它只为同一字段获取一个额外的访问器方法。然而,如果你

class G(var bar: String) extends A(bar)
然后构造一个新字段

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

(并且在
G
中再次出现一个)

public size$G(java.lang.String);
代码:
0:aload_0
1:aload_1
2:putfield#11//字段栏:Ljava/lang/String;
5:aload_0
6:aload_1
7:特别是#18//方法大小为$A.“”:(Ljava/lang/String;)V
10:返回

请注意,var和val都在Scala生成的类文件上创建方法。字段的生成对于用户来说有点不透明,因此您不能依赖生成的任何特定字段或此类字段的名称。
B
也不会为
foo
添加字段,以防您在构造函数体之外访问它,而是使用父级的访问器。感谢您提供的信息。只是想澄清一下:你是说D的实例将有两个foo的副本吗?@alexblack:是的。
javap
命令有助于披露这些细节,但请注意,您需要使用它的
-private
选项查看支持编译器用于调解对这些字段的访问的访问器(和mutator)方法的所有私有字段。
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    
}
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
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