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 definiert ist, erzeugt die Fehler Cannot reference a field before it is defined, was durchaus verständlich ist, da hier die Reihenfolge der Deklaration Angelegenheiten. Aber warum kompiliert sich folgendes?Es scheint, dass ich * ein Feld verweisen kann, bevor es *

public enum MyEnum2 { 

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

    public abstract MyEnum2 getOther(); 

} 

FOO bezieht sich auf BAR vor BAR definiert ist, bin ich falsch?

+0

Sind 'enum'-Konstanten nicht in Strukturen zusammengefasst, die Klassen ähneln? Wenn Sie 'BAR' zurückgeben, beziehen Sie sich auf einen Typ. Lesen Sie [hier] (http://stackoverflow.com/questions/7276775/what-does-java-compile-an-enumeration-down-to): _set der gültigen Werte wird bei der Typinitialisierung erstellt. Time_ –

+0

[JLS] (http : //docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.9.1) sagt _Der optionale Klassenkörper einer Enum-Konstante definiert implizit eine anonyme Klassendeklaration (§15.9. 5) das erweitert den unmittelbar einschließenden Enum-Typ. –

Antwort

2

Die wichtige JLS Teile sind this und this

A Klassen- oder Schnittstellentyp T sofort initialisiert wird, bevor die ersten Auftreten irgendeiner der folgenden:

T ist eine Klasse und einer Instanz von T wird erstellt.

T ist eine Klasse und eine durch T deklarierte statische Methode wird aufgerufen.

Ein von T deklariertes statisches Feld wird zugewiesen.

Ein durch T deklariertes statisches Feld wird verwendet und das Feld ist keine konstante Variable (§4.12.4).

T ist eine Top-Level-Klasse (§7.6), und eine Assert-Anweisung (§14.10) lexikalisch geschachtelt innerhalb T (§8.1.3) wird ausgeführt.

Und

Die optionale Klasse Körper eines ENUM-Konstante definiert implizit eine anonyme Klassendeklaration (§15.9.5), die den unmittelbar umschließenden enum-Typ erstreckt.

So mit

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

Sie erstellen zwei anonyme Klassen MyEnum2 erstreckt.

Wenn BAR ist schließlich Referenz entweder beim Aufruf Foo.getOther() oder ein anderes Stück Code tut MyEnum2.Bar, wird der Typ initialisiert werden.

1

Sie erstellen Enum-Konstante mit Bezug auf noch nicht deklarierte Konstante im ersten Fall. Im zweiten Fall spielt es keine Rolle wegen der Kompilierreihenfolge, die Aufzählungskonstanten werden vor dem Aufzählungskörper kompiliert. Ich würde sagen, das ist der Grund. Wenn dies nicht der Fall ist, würde die Kompilierung früher fehlschlagen, da die Deklaration der abstrakten Methode nach der nicht-abstrakten Methodendeklaration im Körper jeder Enum-Konstante definiert ist.

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

1

Wenn FOO(BAR) schreiben, sind Sie eigentlich den Konstruktor von MyEnum1 Aufrufen und daher BAR hat sein ausgewertet, die zu diesem Zeitpunkt nicht möglich ist, da BAR noch nicht definiert worden.

Wenn FOO {...} schreiben, sind Sie eine neue Enumeration Konstante genannt Schaffung FOO, aber eine neue anonyme Klasse definieren. Da die Klassendefinition nur geladen ('geladen' wie in 'ClassLoader') an diesem Punkt und nichts ist noch ausgewertet, kein Fehler auftritt. Dann wird BAR {...} erstellt, der Rest Ihres Programms wird fortgesetzt, etc., und return BAR; (oder return FOO;) wird nur ausgewertet, wenn Sie einen Methodenaufruf an getOther() machen, was zu diesem Zeitpunkt perfekt möglich ist, da beide Enum-Konstanten glücklich sind an diesem Punkt lebendig.

Verwandte Themen