Worden velden geïnitialiseerd voordat de constructorcode in Java wordt uitgevoerd?

Kan iemand de uitvoer van het volgende programma uitleggen? Ik dacht dat constructors worden geïnitialiseerd vóór instantievariabelen. Dus ik verwachtte dat de uitvoer “XZYY” zou zijn.

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

Antwoord 1, autoriteit 100%

De juiste volgorde van initialisatie is:

  1. Statische variabele initialisatie en statische initialisatieblokken, in tekstuele volgorde, als de klasse nog niet eerder is geïnitialiseerd.
  2. De aanroep van super() in de constructor, expliciet of impliciet.
  3. Initialisatoren van instantievariabelen en instantie-initialisatieblokken, in tekstuele volgorde.
  4. Overige hoofdtekst van constructor na super().

Zie secties §2.17.5 -6 van de Java Virtual Machine-specificatie.


Antwoord 2, autoriteit 56%

Als je naar de gedecompileerde versie van het klassenbestand kijkt

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

Je kunt zien dat de instantievariabele Ybinnen de constructor wordt verplaatst, dus de uitvoeringsvolgorde is als volgt

  1. Bel de constructor van Z
  2. Het activeert de standaardconstructor van X
  3. Eerste regel van X-constructor new Y()wordt aangeroepen.
  4. J afdrukken
  5. X afdrukken
  6. Noem de eerste regel in constructor Z new Y()
  7. Print Y
  8. Z afdrukken

Alle instantievariabelen worden geïnitialiseerd met behulp van constructorinstructies.


Antwoord 3, autoriteit 3%

Als je een constructor aanroept, worden de initialisatiefuncties van de instantievariabele uitgevoerd vóór de hoofdtekst van de constructor.Wat denk je dat de uitvoer van het onderstaande programma is?

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

De hoofdmethode roept de Tester-constructor aan, die een uitzondering genereert. Je zou verwachten dat de catch-clausule deze uitzondering opvangt en Uitzondering opgevangenafdrukt.
Maar als je probeerde het uit te voeren, je
ontdekte dat het niets van dat soort doet en het gooit een StackOverflowError.


Antwoord 4, autoriteit 2%

Om de misvattingen met statische informatie te verduidelijken, verwijs ik gewoon naar dit kleine stukje 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();
  }
}

Verrassing is dat de output als volgt is:

Static Block 1
Instance Block 1
Instance Block 2
Constructor
Static Block 2 (Weird!!)
In Main
Instance Block 1
Instance Block 2
Constructor

Houd er rekening mee dat we een static {}hebben die natwee keer {}wordt genoemd. dit gebeurt omdat we de constructor in het midden plaatsen en de uitvoeringsvolgorde tussenvoegen wanneer de constructor voor het eerst wordt aangeroepen.

Ontdekte dit toen ik aan dit antwoord werkte – https://stackoverflow.com/a/30837385/744133.

In principe zien we dat dit gebeurt:

  1. Tijdens de eerste keer dat een object wordt geïnitialiseerd,
    Initialiseer het huidige object voor zowel statische als instantie-initialisatie vermengd op basis van volgorde van voorkomen

  2. Voor alle volgende initialisaties, voer de instantie-initialisatie alleen uit in de volgorde van optreden, aangezien de statische initialisatie al heeft plaatsgevonden.

Ik moet onderzoeken hoe de mix van overerving, en zowel expliciete als impliciete oproepen naar super en dit dit zal beïnvloeden, en zal updaten met bevindingen. Het zou waarschijnlijk vergelijkbaar zijn met de andere verstrekte antwoorden, behalve dat ze het bij het verkeerde eind hadden met de statische initialisatie.


Antwoord 5

De initialisatievolgorde is gespecificeerd in JLS 12.5:

1.Eerst wordt geheugen toegewezen voor het nieuwe object

2.Vervolgens worden alle instantievariabelen in het object (inclusief de variabelen die in deze klasse en al zijn superklassen zijn gedefinieerd) geïnitialiseerd naar hun standaardwaarden

3.Ten slotte wordt de constructor aangeroepen.


https://stackoverflow.com/questions/26552799/who-run-first-default-values-for-instance-variables-or-super-constructors

Other episodes