webentwicklung-frage-antwort-db.com.de

Werden Felder initialisiert, bevor der Konstruktorcode in Java ausgeführt wird?

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();
    }
}
57
Praveen Kumar

Die korrekte Reihenfolge der Initialisierung lautet:

  1. Initialisierer für statische Variablen und statische Initialisierungsblöcke in Textreihenfolge, wenn die Klasse nicht zuvor initialisiert wurde.
  2. Der super () - Aufruf im Konstruktor, egal ob explizit oder implizit.
  3. Instanzvariableninitialisierer und Instanzinitialisierungsblöcke in textueller Reihenfolge.
  4. Rest des Konstruktors nach super ().

Siehe Abschnitte §2.17.5-6 der Java Virtual Machine-Spezifikation .

83
user207421

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

  1. Aufruf des Konstruktors von Z
  2. Es löst den Standardkonstruktor von X aus.
  3. Erste Zeile des X Konstruktors new Y() wird aufgerufen.
  4. Drucken Sie Y
  5. Drucken Sie X
  6. Rufe die erste Zeile im Konstruktor Z new Y() auf
  7. Y drucken
  8. Drucken Sie Z

Alle Instanzvariablen werden mithilfe von Konstruktoranweisungen initialisiert. 

53
Arun P Johny

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.

1
Vivek

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: 

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

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

1
YoYo