Последовательность инициализации объекта в scala во внутренней иерархии - PullRequest
4 голосов
/ 02 декабря 2011

Я новичок в scala из java и смущен последовательностью инициализации объекта scala во внутренней иерархии. IIRC, в Java, если объект подкласса инициализирован, конструктор его базового класса вызывается перед любым кодом его собственного конструктора. Находясь в скале, у меня совершенно другое поведение. Рассмотрим следующий пример:

class Point(val x: Int, val y: Int){
    val name = this.makeName;

    def makeName: String = {
        println("makeName at super.");

        "[" + x + ", " + y + "]";
    }

    override def toString: String = name;
}

class ColorPoint(override val x: Int, override val y: Int, var color: String) extends Point(x, y) {

    // key statement
    println(name);

    override def makeName: String = {
        println("makeName at sub.");

        super.makeName + ":" + myColor;
    }

    val myColor = color;

    override def toString: String = name;
}

Давайте просто рассмотрим байт-код конструктора ColorPoint, сброшенного с javap. Если код включает в себя ключевое выражение println(name);, то байтовый код будет

public ColorPoint(int, int, java.lang.String);
  Code:
   0:   aload_0
   1:   aload_3
   2:   putfield        #13; //Field color:Ljava/lang/String;
   5:   aload_0
   6:   iload_1
   7:   iload_2
   8:   invokespecial   #18; //Method Point."<init>":(II)V
   11:  getstatic       #24; //Field scala/Predef$.MODULE$:Lscala/Predef$;
   14:  aload_0
   15:  invokevirtual   #28; //Method name:()Ljava/lang/String;
   18:  invokevirtual   #32; //Method scala/Predef$.println:(Ljava/lang/Object;)V
   21:  aload_0
   22:  aload_3
   23:  putfield        #34; //Field myColor:Ljava/lang/String;
   26:  return

Мы видим, что поле myColor инициализируется после invokespecial, то есть после инициализации базового класса.

Если я закомментирую утверждение println(name);, то байт-код будет:

public ColorPoint(int, int, java.lang.String);
  Code:
   0:   aload_0
   1:   aload_3
   2:   putfield        #13; //Field color:Ljava/lang/String;
   5:   aload_0
   6:   aload_3
   7:   putfield        #15; //Field myColor:Ljava/lang/String;
   10:  aload_0
   11:  iload_1
   12:  iload_2
   13:  invokespecial   #20; //Method Point."<init>":(II)V
   16:  return

Мы видим, что поле myColor инициализируется непосредственно перед invokespecial, то есть до инициализации базы.

Тогда в чем причина? Какой-нибудь документ / статья описывает такое поведение?

Кстати, версия моего scala - 2.7.7финал (OpenJDK Server VM, Java 1.6.0_20). Спасибо и всего наилучшего!

1 Ответ

3 голосов
/ 02 декабря 2011

Компилятор просто выполняет все по порядку. Здесь есть некоторая документация.

https://github.com/paulp/scala-faq/wiki/Initialization-Order

Основная часть из этого следующая.

  1. Суперклассы полностью инициализируются перед подклассами.
  2. В противном случае в порядке декларирования.
...