2013-08-22 10 views
5
public enum MyEnum1 { 

    FOO(BAR), BAR(FOO); 

    private MyEnum1 other; 

    private MyEnum1(MyEnum1 other) { 
     this.other = other; 
    } 

    public MyEnum1 getOther() { 
     return other; 
    } 

} 

MyEnum1 genera l'errore Cannot reference a field before it is defined, che è abbastanza comprensibile, dal momento che le questioni di ordine dichiarazione qui. Ma perché compila il seguente?Sembra che posso * riferimento a un campo prima che venga definita *

public enum MyEnum2 { 

    FOO { public MyEnum2 getOther() { return BAR; } }, 
    BAR { public MyEnum2 getOther() { return FOO; } }; 

    public abstract MyEnum2 getOther(); 

} 

FOO si riferisce alla prima BARBAR è definito, mi sbaglio?

+0

Le costanti di 'enum' non sono compilate in strutture simili alle classi? Tornando a 'BAR', ti stai effettivamente riferendo a un tipo. Leggi [qui] (http://stackoverflow.com/questions/7276775/what-does-java-compile-an-enumeration-down-to): _set di valori validi viene creato al momento dell'inizializzazione del tipo_ –

+0

[JLS] (http : //docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.9.1) dice _Il corpo facoltativo della classe di una costante enum definisce implicitamente una dichiarazione di classe anonima (§15.9. 5) che estende il tipo di enum immediatamente racchiuso. –

risposta

2

Le parti importanti GLS sono this e this

Una classe o interfaccia tipo T viene inizializzato immediatamente prima del primo verificarsi di uno qualsiasi dei seguenti:

T è una classe ed un l'istanza di T è creata.

T è una classe e viene invocato un metodo statico dichiarato da T.

Viene assegnato un campo statico dichiarato da T.

Un campo statico dichiarato da T viene utilizzato e il campo non è una variabile costante (§4.12.4).

T è una classe di livello superiore (§7.6) e viene eseguita un'istruzione di asserzione (§14.10) annidata lessicale in T (§8.1.3).

E

Il corpo della classe facoltativa di un costante enum definisce implicitamente una dichiarazione di classe anonima (§15.9.5) che si estende il tipo enum immediatamente racchiude.

Quindi, con

FOO { public MyEnum2 getOther() { return BAR; } }, 
BAR { public MyEnum2 getOther() { return FOO; } }; 

si sta creando due classi anonime che si estende MyEnum2.

Quando BAR è di riferimento quando si chiama Foo.getOther() o qualche altra parte di codice è MyEnum2.Bar, il tipo verrà inizializzato.

1

si sta creando costante enum con riferimento a costante non dichiarata nel primo caso. Nel secondo caso non importa a causa dell'ordine di compilazione, le costanti di enumerazione sono compilate prima del corpo di enumerazione. Direi che questo è il motivo. Se non era vero, la compilazione fallirebbe prima perché la dichiarazione del metodo astratto viene definita dopo la dichiarazione del metodo non astratto nel corpo di ciascuna costante enum.

buon riferimento - http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.9

1

Quando si scrive FOO(BAR), in realtà si sta invocare il costruttore di MyEnum1 e quindi BAR deve essere valutata , che è impossibile in quel momento poiché BAR non è stato ancora definito.

Quando si scrive FOO {...}, si sono creando una nuova costante enum chiamato FOO, ma definendo una nuova classe anonima. Poiché la definizione della classe è solo caricata ("caricata" come in "ClassLoader") a questo punto e nulla è ancora valutato, non si verifica alcun errore. Quindi, BAR {...} viene creato, il resto del programma continua, ecc. E return BAR; (o return FOO;) è solo valutato quando si effettua una chiamata di metodo a getOther(), che è perfettamente possibile a quel punto poiché entrambe le costanti di enumerazione sono felicemente vivo a quel punto.