2015-12-16 7 views
6
class DemoClass { 
    public static void main(String args[]) { 
     System.out.println("Start"); 
     A a=new D(); 
    } 
} 
class A { 
    static { 
     System.out.println("Static A"); 
     A c=new C(); 
    } 

    public A() { 
     System.out.println("Constr A"); 
    } 
} 

class B extends A { 
    static { 
     System.out.println("Static B"); 
    } 

    public B() { 
     System.out.println("Constr B"); 
    } 
} 

class C extends B { 
    static { 
     System.out.println("Static C"); 
    } 

    public C() { 
     System.out.println("Constr C"); 
    } 
} 

class D extends C { 
    static { 
     System.out.println("Static D"); 
    } 

    public D() { 
     System.out.println("Constr D"); 
    } 
} 

Die Reihenfolge der Ausführung für obigen Code ist:Wann wird der statische Block in JAVA beim Erstellen eines Objekts ausgeführt?

Start 
Static A 
Constr A 
Constr B 
Constr C 
Static B 
Static C 
Static D 
Constr A 
Constr B 
Constr C 
Constr D 

Meine Ansicht nach all statischen Blöcke sollten zunächst dann nur das Objekt ausgeführt werden, erstellt werden. Aber hier wird zuerst das Objekt "A c = new C()" in einem statischen Block der Klasse A erzeugt und dann werden die anderen statischen Blöcke ausgeführt. Warum?

+3

Als beiseite, ich vermute, dass Sie dies mit drei Klassen unter Beweis gestellt haben könnte oder möglicherweise nur 2 genauso gut - und machte Es ist einfacher, eine umfassende Liste von Ereignissen bereitzustellen. –

Antwort

13

Der statische Initialisierer aller Klassen hat gestartet ausgeführt - aber um D zu initialisieren, muss C initialisiert werden, daher muss B initialisiert werden, daher muss A initialisiert werden. An dem Punkt, an dem der Code in dem statischen Initialisierer in A ausgeführt wird, befinden sich alle beteiligten Klassen in einem Zustand, in dem sie "initialisiert" werden.

Im statischen Initialisierer von A es eine Instanz von C konstruiert - aber C ist bereits initialisiert wird, so dass die Initialisierung nicht wieder starten ... die JVM stellt fest, nur, dass es bereits ist (innerhalb der initialisiert wird gleichen Thread) und geht weiter.

Die Details von allem sind in JLS 12.4.2. Insbesondere die Kugel:

Wenn das Objekt für ClassC zeigt an, dass sich in der Initialisierungsphase für C durch den aktuellen Thread ist, so muss diese eine rekursive Anfrage zur Initialisierung sein. Geben Sie LC frei und führen Sie sie normal aus.

und

Als nächstes, wenn C eine Klasse anstatt eine Schnittstelle ist, und seine Oberklasse noch nicht initialisiert wurde, dann SC seine Oberklasse sein lassen und lassen SI1, ..., SiN sein alle Superschnittstellen von C, die mindestens eine Standardmethode deklarieren. [...]

Führen Sie für jedes S in der Liste [SC, SI1, ..., SIn] die gesamte Prozedur für S rekursiv durch. Falls erforderlich, überprüfen und erstellen Sie S zuerst.

... sind relevant.

+0

Ich bin verwirrt über "Constr B" vor "Static B". Hast du einen Vorschlag? – Mikey

+1

@Mikey: Es ist genau das Gleiche - es ist Teil der Konstruktion eines C, was passiert, während der * body * des statischen Initializers für A ausgeführt wird. –

-2

wenn Jvm zu diesem Zeitpunkt alle statischen Mitglied loszulegen werden gescannt und Speicher für sie zugeordnet werden, dann wird es für keine statische gehen ..

so zuerst wird es statische Druck dann nicht statisch

+0

Ich glaube nicht, dass Sie die Frage sorgfältig gelesen haben. –

5

@JonSkeet hat alles technisch gesagt und ich kann nicht mehr sagen. Lassen Sie mich versuchen, eine Analogie zu erklären:

Denken Sie an statische Initialisierung als Öffnen einer Tür eines Raumes und Konstruktorausführung als das Ausführen von Dingen in diesem Raum.

Nun, um die Tür von Raum D zu öffnen, müssen Sie Tür von C öffnen, für C brauchen Sie B und für B brauchen Sie A. Jetzt sind Sie in Raum A und Sie haben Türöffnung Formalitäten in Raum A. Und während Sie die Türöffnungsformalitäten in Raum A beenden, sehen Sie eine Notiz, die die Arbeit von Raum C beendet (A c=new C();). Jetzt, da der Raum C und seine abhängigen Räume bereits offen sind, müssen Sie nicht wieder öffnen (bedeutet keine statische Blockinitialisierung).Aber bevor Sie auf Raum C gehen Sie den Raum Beende eine Formalitäten Öffnung System.out.println("Static A"); So also, in der Konsole Sie haben:

Static A

Nun, Sie sind im Raum C und Sie müssen beenden diesen Raum aber davor haben Sie B und A wegen der Abhängigkeit beendet (C erstreckt sich B und B erstreckt sich A). Also, in der Konsole Sie haben:

Konstruktionsmat A Konstruktionsmat B Konstruktionsmat C

Nun werden Sie wieder auf Raum zurück A und sehen Sie Tür öffnen Formalitäten abgeschlossen. Also, Sie kommen auf Raum B dann C und dann D. Also, in der Konsole Sie haben:

Static B Static C Statische D

Jetzt, Sie sind Finishing-Job von Raum D (A a=new D();) und dazu müssen Sie den Job von C, B und C wegen der Abhängigkeit beenden (D erweitert C, C erweitert B und B erweitert A). Also, in der Konsole Sie haben:

Konstruktionsmat A Konstruktionsmat B Konstruktionsmat C Konstruktionsmat D