2013-08-22 25 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 generuje błąd Cannot reference a field before it is defined, co jest dość zrozumiałe, gdyż sprawach porządkowych deklaracja tutaj. Ale dlaczego poniższe kompilacje?Wydaje się, że mogę odwołać * pola zanim zostanie zdefiniowany *

public enum MyEnum2 { 

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

    public abstract MyEnum2 getOther(); 

} 

FOO dotyczy BAR przed BAR jest zdefiniowana, nie mam racji?

+0

Czy nie są stałe "enum" skompilowane do struktur podobnych do klas? Zwracając 'BAR', faktycznie odnosisz się do typu. Przeczytaj [tutaj] (http://stackoverflow.com/questions/7276775/what-does-java-compile-an-enumeration-down-to): _set prawidłowych wartości jest tworzony przy czasie inicjowania typu_ –

+0

[JLS] (http : //docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.9.1) mówi _Opcjonalny korpus klasy stałej wyliczeniowej domyślnie definiuje anonimową deklarację klasy (§15.9. 5), który rozszerza natychmiast zamykający typ wyliczeniowy. –

Odpowiedz

2

ważne części na trasę są this i this

klasy lub interfejs typu T będzie inicjowane zaraz przed pierwszego wystąpienia jednego z następujących:

T oznacza klasę i AN instancja T jest tworzona.

T jest klasą i wywoływana jest metoda statyczna zadeklarowana przez T.

Pole statyczne zadeklarowane przez T jest przypisane.

Stosowane jest pole statyczne zadeklarowane przez T, a pole nie jest stałą zmienną (§4.12.4).

T jest klasą najwyższego poziomu (§ 7.6), a wykonywana jest instrukcja assert (§14.10) leksykalnie zagnieżdżona w T (§8.1.3).

I

Opcjonalny ciało klasa o stałej enum dorozumiany określa anonimowy deklarację klasy (§15.9.5), która rozciąga się od razu otaczającą typu enum.

Więc z

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

tworzysz dwie klasy anonimowych rozszerzenie MyEnum2.

Gdy BAR jest ostatecznie odniesienie, gdy zadzwonisz Foo.getOther() lub inny kod MyEnum2.Bar, typ zostanie zainicjowany.

1

Tworzysz stałą wyliczeniową w odniesieniu do niezadeklarowanej stałej w pierwszym przypadku. W drugim przypadku nie ma znaczenia ze względu na kolejność kompilacji, stałe wyliczeniowe są kompilowane przed ciałem wyliczeniowym. Powiedziałbym, że to jest powód. Gdyby nie było to prawdą, kompilacja zawiodłaby wcześniej, ponieważ deklaracja metody abstrakcyjnej jest zdefiniowana po nieekspozycyjnej deklaracji metody w ciele każdej stałej wyliczeniowej.

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

1

Pisząc FOO(BAR), w rzeczywistości wywoływania konstruktora MyEnum1 i dlatego BAR musi być oceniano, co jest niemożliwe w tej chwili od BAR nie została jeszcze określona.

Pisząc FOO {...}, jesteś tworzenia nowe wyliczenia stałej nazywany FOO, ale definiowania nowa klasa anonimowy. Ponieważ definicja klasy jest tylko załadowana ("załadowane" jak w "ClassLoader") w tym momencie i nic nie jest jeszcze oceniane oceniane, nie występuje błąd. Następnie tworzony jest BAR {...}, reszta programu jest kontynuowana, itd., A return BAR; (lub return FOO;) jest tylko obliczona po wywołaniu metody na getOther(), co jest w tym przypadku całkowicie możliwe, ponieważ obie stałe są stałe żyje w tym momencie.