2015-04-15 30 views
14

Volevo creare un enum in cui a ogni costante è associato uno Map. Ho compiuto questo dando ogni costante inizializzatore un'istanza, così:Perché questo enum viene compilato?

import java.util.HashMap; 
import java.util.Map; 

public enum Derp { 
    FOO {{ 
      mMap.put("bar", 1); 
     }}; 

    // cannot be private 
    protected final Map<String, Integer> mMap = new HashMap<>(); 
} 

ho scoperto che se mMap è private, non può essere fatto riferimento nel caso di inizializzazione. L'errore è Cannot make a static reference to the non-static field mMap. Prima che la ragione di questo si è verificato a me, ho consultato JLS §8.9.2, che dice in parte:

Si tratta di un errore di compilazione per i costruttori, blocchi esempio di inizializzazione, o un'istanza espressioni di inizializzazione delle variabili di un enum costanti e a fare riferimento a e oa una costante enum dello stesso tipo dichiarata a destra di e.

non sono io infrangendo questa regola implicitamente riferimento FOO nella propria istanza intializer FOO s'? Come si compila? Non solo compila, ma funziona correttamente in fase di runtime.

(Mi venne in mente che non può essere mMapprivate perché sto implicitamente la creazione di una sottoclasse anonima che non può fare riferimento a un campo private nella sua superclasse. Che è un po 'strano di per sé dal momento che le enumerazioni sono implicitamente final ...)

+1

"enumerazioni sono implicitamente' final'" - [non del tutto] (http://ideone.com/3bi0U1). Java ha bisogno di creare sottoclassi implicite per ogni istanza ogni volta che si fa il problema con le parentesi accanto a una costante enum, quindi se lo fai, la classe enum non è definitiva. Tuttavia, non puoi ancora dichiarare le tue sottoclassi. – user2357112

+1

Qualifica la chiamata come 'super.mMap.put (...);'. La ragione di questo è solo una specifica strana. – Radiodef

+0

@Radiodef Non sono convinto che si tratti di un duplicato. Penso che questo poster faccia due domande che non sono state poste nel post collegato: (1) perché è legale se usa 'protected' e (2) perché non è l'autoreferenziale implicito illegale. Ho esaminato le risposte lì e non rispondono alla domanda con mia soddisfazione. – ajb

risposta

4

è un errore di compilazione per i costruttori, blocchi esempio di inizializzazione, o istanza espressioni di inizializzazione variabili di un'enumerazione costanti e per riferirsi a e o meno di una costante enum dello stesso tipo di quello dichiarato al diritto di e.

La specifica qui significa solo che non è possibile fare riferimento per nome perché il campo a cui si riferisce e non è ancora inizializzato. Ciò non significa che non è possibile accedere a this.

È praticamente la stessa regola di qualsiasi altro inizializzatore (come int x = x;).

Possiamo vedere il motivo per cui con un esempio come (Ideone):

enum Example { 
    INSTANCE {{ 
     subversion(); 
    }}; 

    static void subversion() { 
     System.out.println(INSTANCE); 
    } 

    public static void main(String[] args) { 
     System.out.println(INSTANCE); 
    } 
} 

quali uscite

null 
INSTANCE 

ho scoperto che se mMap è privato, non può essere fatto riferimento in l'inizializzatore dell'istanza.

È possibile qualificare la chiamata come super.mMap.put(...);. Il privato mMap non è ereditato, ma è accessibile dalla classe interna. I also covered this here. In breve, il semplice nome mMap fa riferimento a un'istanza esterna inesistente di Derp.

possiamo verificare questo è il caso con un esempio come (Ideone):

class Example { 
    private int x; 

    class Inner extends Example {{ 
     x = 1;  // refers to the outer instance 
     super.x = 2; // refers to the inner instance 
    }} 

    public static void main(String[] args) { 
     Example outer = new Example(); 
     Example inner = outer.new Inner(); 
     System.out.println(outer.x); // prints 1 
     System.out.println(inner.x); // prints 2 
    } 
} 

Tranne nel caso FOO è statico quindi non c'è alcun esempio esterno — quindi errore di compilatore.

1

È perché FOO è la propria sottoclasse anonima di Derp - che esiste già quando viene creato FOO.

public class Enums { 
    public enum Derp { 
     FOO {{ 
      mMap.put("bar", 1); 
     }}; 

     // cannot be private 
     protected final Map<String, Integer> mMap = new HashMap<>(); 
    } 

    public static void main(String[] args) { 
     System.out.println(Derp.class); 
     System.out.println(Derp.FOO.getClass()); 
    } 
} 

classe Enums $ Derp
classe Enums $ Derp $ 1

Problemi correlati