2012-08-02 7 views
8

Konstruktor wird von Effective Java:Ausführungsreihenfolge von der statischen Blöcke in einer Enum-Typ WRT Dieser

// Implementing a fromString method on an enum type 
    private static final Map<String, Operation> stringToEnum 
     = new HashMap<String, Operation>(); 

    static { // Initialize map from constant name to enum constant 
    for (Operation op : values()) 
     stringToEnum.put(op.toString(), op); 
    } 

    // Returns Operation for string, or null if string is invalid 
    public static Operation fromString(String symbol) { 
    return stringToEnum.get(symbol); 
    } 

Beachten Sie, dass die Betriebskonstanten in die Karte stringToEnum setzen von einem statischen Block, der nach läuft Die Konstanten wurden erstellt. Der Versuch, die Konstanten so zu setzen, dass sie sich in einem eigenen Konstruktor befinden, würde einen Kompilierungsfehler verursachen. Das ist eine gute Sache, weil es eine NullPointerException verursachen würde, wenn es legal wäre. Enum Konstruktoren dürfen nicht auf die statischen Felder der Enumeration zugreifen, , mit Ausnahme von Konstantenfeldern zur Kompilierungszeit. Diese Einschränkung ist notwendig , da diese statischen Felder noch nicht initialisiert wurden, wenn die -Konstruktoren ausgeführt werden.

Meine Frage ist in Bezug auf die Zeile:

„Beachten Sie, dass die Betriebskonstanten in die Karte stringToEnum gesetzt werden von einem statischen Block, der ausgeführt wird, nachdem die Konstanten erstellt worden sind“.

Ich dachte, der statische Block wird ausgeführt, bevor der Konstruktor ausgeführt wird. Die werden tatsächlich während der Ladezeit der Klasse ausgeführt.

Was fehlt mir hier?

+0

Siehe http://stackoverflow.com/questions/3028219/are-there-any-guarantees-in-jls-about-order-of-execution-static -initialisierung-b –

Antwort

11

Ich verstehe Ihre Frage als: Warum gibt es eine Garantie, dass die Enum-Konstanten initialisiert werden, bevor der statische Block ausgeführt wird. Die Antwort liegt in den JLS gegeben, und ein spezifisches Beispiel ist in #8.9.2.1 mit der folgenden Erklärung gegeben:

statische Initialisierung von oben nach unten stattfindet.

und die enums-Konstanten sind implizit endgültig statisch und werden vor dem statischen Initialisierungsblock deklariert.

EDIT

Das Verhalten ist von einer normalen Klasse nicht anders. Der folgende Code druckt:

In constructor: PLUS 
PLUS == null MINUS == null 

In constructor: MINUS 
PLUS != null MINUS == null 

In static initialiser 
PLUS != null MINUS != null 

In constructor: after static 
PLUS != null MINUS != null 
public class Operation { 

    private final static Operation PLUS = new Operation("PLUS"); 
    private final static Operation MINUS = new Operation("MINUS"); 

    static { 
     System.out.println("In static initialiser"); 
     System.out.print("PLUS = " + PLUS); 
     System.out.println("\tMINUS = " + MINUS); 
    } 

    public Operation(String s) { 
     System.out.println("In constructor: " + s); 
     System.out.print("PLUS = " + PLUS); 
     System.out.println("\tMINUS = " + MINUS); 
    } 

    public static void main(String[] args) { 
     Operation afterStatic = new Operation ("after static"); 
    }  
} 
+0

sagen die Operation stellt die Operation eines Rechners. Und die Konstanten (PLUS, MINUS, DIVIDE, MULTIPLY) werden erst nach dem Ausführen des Konstruktors erzeugt. Daher bin ich verwirrt darüber, wie die Konstanten vor der Ausführung des Konstruktors initialisiert werden können.Die impliziten statischen Endfelder, die die Konstanten enthalten, können vor dem Konstruktor erstellt werden, sie können jedoch erst zugewiesen werden, nachdem der Konstruktor ausgeführt wurde. – Geek

+1

Jede Konstante (PLUS, MINUS ...) wird initialisiert, nachdem ihr entsprechender Konstruktor ausgeführt wurde. Die Reihenfolge der Ausführung, wenn Sie möchten, wird sein: 'PLUS = new Operation (...); MINUS = neue Operation (...); ...; static block' – assylias

+0

Das ist der Grund, warum Bloch sagt, dass wenn Sie versuchen, die Map aus den Konstruktoren aufzufüllen, weil die Konstanten nicht initialisiert wurden, bis alle Konstruktoren fertig sind. – assylias

0

Operation Konstanten sind statische Felder, die im statischen Block in der erscheinenden Reihenfolge erstellt werden.

static { 
    // instantiate enum instances here 
    ... 
    // Initialize map from constant name to enum constant  
    for (Operation op : values())  
     stringToEnum.put(op.toString(), op); 
} 
0

Die static Blöcke ausführen in der Reihenfolge des Erscheinens (Sie mehrere statische Blöcke haben kann), wenn der Klassenlader die Klasse lädt, zB. Es wird vor dem Konstruktor ausgeführt.