Domanda

Sono nuovo di scala da java e sono confuso dalla sequenza di inizializzazione degli oggetti di scala in una gerarchia intrinseca. IIRC, in Java, se viene inizializzato un oggetto della sottoclasse, il costruttore della sua classe base viene richiamato prima di qualsiasi codice del proprio costruttore. Mentre sono in scala, ottengo un comportamento completamente diverso. Considera il seguente esempio:

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

Consideriamo solo il byte code del costruttore di ColorPoint scaricato con javap. Se il codice include l'istruzione chiave println(name);, il byte code è

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

Possiamo vedere che il campo myColor viene inizializzato dopo invokespecial, ovvero dopo l'inizializzazione della classe base.

Se commento l'istruzione println(name);, il byte code è:

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

Vediamo che il campo myColor viene inizializzato appena prima di invokespecial, ovvero prima dell'inizializzazione di base.

Allora qual è il motivo? Qualche documento / articolo specifica questo tipo di comportamento?

A proposito, la versione di my scala è 2.7.7final (OpenJDK Server VM, Java 1.6.0_20). Grazie e cordiali saluti!

È stato utile?

Soluzione

Il compilatore sta semplicemente eseguendo le cose in ordine.C'è della documentazione qui.

https://github.com/paulp/scala-faq/wiki/Ordine di inizializzazione

La parte principale è la seguente.

  1. Le superclassi sono completamente inizializzate prima delle sottoclassi.
  2. Altrimenti, in ordine di dichiarazione.
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top