Ein Objekt statisch erstellen

68

Könnte jemand erklären, wie Java diesen Code ausführt? Ich meine die Reihenfolge der Ausführung jeder Anweisung.

public class Foo
{
    boolean flag = sFlag;
    static Foo foo = new Foo();
    static boolean sFlag = true;

    public static void main(String[] args)
    {
        System.out.println(foo.flag);
    }
}

AUSGABE:

false
Eng.Fouad
quelle
4
Wir sind Menschen, keine Computer. Sollten wir versuchen, Code einfacher zu gestalten, anstatt diese Art von Tricks oder Fallen oder was auch immer zu verwenden ...
Don Li
1
+1, weil es keine schwierige, aber gute Frage ist, die sicher anderen helfen wird, die Sprache und insbesondere den statischen Modifikator besser zu verstehen. Sehr nützliche Antwort von @JonSkeet zu einem etwas wichtigen - aber oft unterschätzten - Thema.
Jorey
1
Ich mag es nicht, wenn Leute 'Foo' benutzen. Verwenden Sie echte Begriffe: /
contactmatt

Antworten:

104
  • Die Klasseninitialisierung beginnt. Anfangs fooist null und sFlagfalsch
  • Der erste statische Variableninitialisierer ( foo) wird ausgeführt:
    • Eine neue Instanz von Foowird erstellt
    • Der Instanzvariableninitialisierer für flagExecutes - ist derzeit sFlagfalse, daher ist der Wert von flagfalse
  • Die zweite statische Variable initializer ( sFlag) wird ausgeführt und setzt den Wert auf true
  • Die Klasseninitialisierung ist abgeschlossen
  • mainläuft, druckt aus foo.flag, was falsch ist

Beachten Sie, dass wenn sFlages als solche deklariert finalwürde, es als Kompilierungszeitkonstante behandelt würde. Zu diesem Zeitpunkt würden alle Verweise darauf im Grunde genommen inline sein true, foo.flagwas auch wahr wäre.

Jon Skeet
quelle
Ist es wichtig, in welcher Reihenfolge die Variablen in der Klasse definiert sind? dh wenn flagwurde nach definiert sflag?
Naveen
@Naveen IMHO, ich denke nicht. statische Variablen werden zuerst initialisiert.
Eng.Fouad
1
@Naveen: Die Reihenfolge wichtig, dass , wenn sFlagvor dem erklärt wurde foo, dass Materie würde - aber sFlagund flagOrdnung spielt keine Rolle.
Jon Skeet
5
statische Elemente werden in der Reihenfolge initialisiert, in der sie deklariert sind. Wenn Sie sFlag deklarieren, bevor die Instanz erstellt wird, ist die Ausgabe wahr.
Drona
1
@ClintHui: Bei Konstanten zur Kompilierungszeit werden ihre konstanten Werte überall dort verwendet, wo auf das konstante Feld verwiesen wird, anstatt tatsächlich auf das Feld zuzugreifen. Es spielt also keine Rolle, dass das Feld noch nicht auf seinen Wert gesetzt wurde.
Jon Skeet
12

foo wird während der statischen Initialisierung der Klasse und vor der Initialisierung von sFlag instanziiert, und der Standardwert eines Booleschen Werts ist false.

  1. Die Klasse wird geladen
  2. Foo wird für die Instanz initialisiert

    2.a Das Instanzmitgliedsflag wird auf den Wert von sFlag initialisiert ( falsestandardmäßig).

  3. sFlag wird auf true initialisiert

Weitere Informationen finden Sie in JLS §12.4 .

MByD
quelle
5

Wenn die Klasse geladen wird sFlagund die fooFelder initialisiert werden, foowird sie zuerst initialisiert!
Felder flagund sFlagsind boolesch und können nicht null sein. Standardmäßig sind sie also falsch und sFlagbei fooder Initialisierung immer noch falsch . flag = sFlagdanach flagist falsch. Das ist es

shift66
quelle
2

Die allgemeine Reihenfolge der Initialisierungsoperationen lautet (nach dem Laden der Klasse und vor der ersten Verwendung):

  1. Statische (Klassen-) Codeblöcke in der Reihenfolge, in der sie im Code erscheinen.
  2. Objektcode-Blöcke in der Reihenfolge, in der sie im Code angezeigt werden (Initialisierungsblöcke und Zuweisungen).
  3. Konstruktoren

Sicherlich bezeichne ich Konstruktoren und Funktionskörper oben nicht als Codeblock .

Ich weiß nicht wie über final staticFelder. Es sieht so aus, als ob sie den Regeln der staticFelder folgen und vor der Deklaration nicht referenziert werden können, obwohl zuvor kommentiert wurde, dass sie beim Kompilierungsschritt initialisiert wurden. Wenn auf sie verwiesen wird, bevor ein Kompilierungsfehler auftritt:

Example.java:8: illegal forward reference
        System.err.println("1st static block j=" + j);

Möglicherweise können final staticFelder initialisiert und in die Klassendatei kompiliert werden, dies ist jedoch keine allgemeine Regel und kann vor der Deklaration immer noch nicht referenziert werden.

Beispielcode zur Überprüfung der Initialisierungsreihenfolge:

class Example {    

    final static int j = 5;

    {
        System.err.println("1st initializer j=" + j);
    }

    static {
        System.err.println("1st static block j=" + j);
    }

    static {
        System.err.println("2nd static block j=" + j);
    }

    final static java.math.BigInteger i = new java.math.BigInteger("1") {    
        {
            System.err.println("final static anonymous class initializer");
        }
    };

    Example() {
        System.err.println("Constructor");
    }

    static {
        System.err.println("3nd static block j=" + j);
    }

    {
        System.err.println("2nd initializer");
    }

    public static void main(String[] args) {
        System.err.println("The main beginning.");
        Example ex = new Example();
        System.err.println("The main end.");
    } 
}

Das obige Code-Snipset wird gedruckt:

1st static block j=5
2nd static block j=5
final static anonymous class initializer
3nd static block j=5
The main beginning.
1st initializer j=5
2nd initializer
Constructor
The main end.
digital_infinity
quelle
JVM-Spezifikation Detaillierte Initialisierungsprozedur
digital_infinity
1

zuerst sollten statische Felder laufen und zuerst inline! In der ersten Zeile 4 und dann wird 5 ausgeführt, sodass foo zuerst initialisiert wird. Wie wir wissen, werden boolesche Variablen standardmäßig auf false initialisiert. Wenn also foo initialisiert wird, ist das Flag-Feld zunächst sflag, das false ist, und dann wird sfalsg true Flag wird nicht geändert (es gibt keine Beziehung), dann endlich Hauptläufe und Falg drucken, das ist falsch !!! Ich hoffe nützlich zu sein! Erfolgreich sein

FM
quelle