Objektinitialisierungssequenz in Scala in einer inhärenten Hierarchie
Frage
Ich bin neu in Scala aus Java und verwirrt durch die Abfolge der Objektinitialisierung von Scala in einer inhärenten Hierarchie. IIRC: Wenn in Java ein Objekt der Unterklasse initialisiert wird, wird der Konstruktor seiner Basisklasse vor jedem Code seines eigenen Konstruktors aufgerufen. Während ich in der Scala bin, verhalte ich mich ganz anders. Betrachten Sie das folgende Beispiel:
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;
}
Betrachten wir einfach den Bytecode des Konstruktors des ColorPoint
, der mit javap
ausgegeben wird. Wenn der Code die Schlüsselanweisung println(name);
enthält, lautet der Bytecode
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
Wir können sehen, dass das Feld myColor
nach invokespecial
, d. h. nach der Initialisierung der Basisklasse, initialisiert wird.
Wenn ich die Anweisung println(name);
auskommentiere, lautet der Bytecode:
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
Wir sehen, dass das Feld myColor
unmittelbar vor dem invokespecial
initialisiert wird, d. h. bevor die Basis initialisiert wird.
Was ist dann der Grund? Jedes Dokument / Artikel spezifiziert diese Art von Verhalten?
Übrigens, Version meiner Scala ist 2.7.7final (OpenJDK Server VM, Java 1.6.0_20). Danke und beste Grüße!
Lösung
Der Compiler führt die Dinge einfach der Reihe nach aus.Hier finden Sie einige Dokumentationen.
https://github.com/paulp/scala-faq/wiki/Initialisierungsreihenfolge
Der Hauptteil davon ist der folgende.
- Superklassen werden vor Unterklassen vollständig initialisiert.
- Andernfalls in Deklarationsreihenfolge.