Kann jemand die Ausgabe des folgenden Programms erklären? Ich dachte, Konstruktoren werden vor Instanzvariablen initialisiert. Ich habe also erwartet, dass die Ausgabe "XZYY" ist.
class X {
Y b = new Y();
X() {
System.out.print("X");
}
}
class Y {
Y() {
System.out.print("Y");
}
}
public class Z extends X {
Y y = new Y();
Z() {
System.out.print("Z");
}
public static void main(String[] args) {
new Z();
}
}
Die korrekte Reihenfolge der Initialisierung lautet:
Siehe Abschnitte §2.17.5-6 der Java Virtual Machine-Spezifikation .
Wenn Sie sich die dekompilierte Version der Klassendatei ansehen
class X {
Y b;
X() {
b = new Y();
System.out.print("X");
}
}
class Y {
Y() {
System.out.print("Y");
}
}
public class Z extends X {
Y y;
Z() {
y = new Y();
System.out.print("Z");
}
public static void main(String args[]) {
new Z();
}
}
Sie können feststellen, dass die Instanzvariable y
innerhalb des Konstruktors verschoben wird. Die Ausführungssequenz lautet daher wie folgt
Z
X
aus.X
Konstruktors new Y()
wird aufgerufen.new Y()
aufY
druckenAlle Instanzvariablen werden mithilfe von Konstruktoranweisungen initialisiert.
Wenn Sie einen Konstruktor aufrufen, werden die Instanzen der Instanzvariablen vor dem Rumpf des Konstruktors ausgeführt. Was denkst du über die Ausgabe des untenstehenden Programms?
public class Tester {
private Tester internalInstance = new Tester();
public Tester() throws Exception {
throw new Exception("Boom");
}
public static void main(String[] args) {
try {
Tester b = new Tester();
System.out.println("Eye-Opener!");
} catch (Exception ex) {
System.out.println("Exception catched");
}
}
}
Die Hauptmethode ruft den Tester-Konstruktor auf, der eine Ausnahme auslöst. Sie können erwarten, dass die catch-Klausel diese Ausnahme abfängt und Exception catched . Ausgibt. Wenn Sie es jedoch ausgeführt haben, haben Sie festgestellt, dass __ nichts davon tut, und es wirft eine StackOverflowError
.
Um die Missverständnisse mit statisch zu klären, verweise ich einfach auf diesen kleinen Code:
public class Foo {
{ System.out.println("Instance Block 1"); }
static { System.out.println("Static Block 1"); }
public static final Foo FOO = new Foo();
{ System.out.println("Instance Block 2"); }
static { System.out.println("Static Block 2 (Weird!!)"); }
public Foo() { System.out.println("Constructor"); }
static public void main(String p[]) {
System.out.println("In Main");
new Foo();
}
}
Überraschung ist, dass die Ausgabe wie folgt ist:
Static Block 1
Instance Block 1
Instance Block 2
Constructor
Static Block 2 (Weird!!)
In Main
Instance Block 1
Instance Block 2
Constructor
Beachten Sie, dass wir einen static {}
haben, der after zwei Instanz {}
heißt. Dies geschieht, weil wir den Konstruktor in die Mitte werfen und die Ausführungsreihenfolge beim ersten Aufruf des Konstruktors einschalten.
Habe dies entdeckt, als ich an dieser Antwort arbeitete - https://stackoverflow.com/a/30837385/744133 .
Grundsätzlich beobachten wir, dass dies geschieht:
Beim ersten Initialisieren eines Objekts wird das aktuelle Objekt sowohl für die statische als auch für die Instanzinitialisierung entsprechend der Reihenfolge des Auftretens initialisiert
Führen Sie für alle nächsten Initialisierungen nur die Instanzinitialisierung in der Reihenfolge des Auftretens aus, da die statische Initialisierung bereits stattgefunden hat.
Ich muss herausfinden, wie die Mischung aus Vererbung und expliziten und impliziten Aufrufen von Super funktioniert. Es ist wahrscheinlich den anderen bereitgestellten Antworten ähnlich, außer dass sie bei der statischen Initialisierung einen Fehler gefunden haben.