Добавляет ли расширение класса в scala с помощью параметров конструктора vals (поля) к классу? - PullRequest
11 голосов
/ 10 сентября 2010

Скажи, что у меня есть:

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 ]

14 голосов
/ 10 сентября 2010

Все компилируемые примеры (A, B, D, E) занимают одинаковое количество дискового пространства.Фактически, даже

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

будет хранить данные в одном поле - он просто получает дополнительный метод доступа для того же поля.Однако, если вы

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

, создается новое поле.

Вы можете проверить все это, скомпилировав свои примеры выше и посмотрев байт-код из javap -c Classname (обратите внимание на поле put2: в конструкторе A):

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 ...)

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
7 голосов
/ 10 сентября 2010

Для класса 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 использует для получения возвращаемого значения?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...