2013-06-06 9 views
10

questo codice:Perché posso sottoclasse anonimamente un enum ma non una classe finale?

public class Sandbox { 
    public enum E { 
     VALUE { 
      @Override 
      public String toString() { 
       return "I'm the value"; 
      } 
     }; 

     @Override 
     public String toString() { 
      return "I'm the enum"; 
     } 
    } 
    public static void main(String[] args) { 
     System.out.println(E.VALUE); 
    } 
} 

stampe:

I'm the value

Tuttavia, questo codice:

public class Sandbox { 
    public static final class C { 
     @Override 
     public String toString() { 
      return "I'm a C"; 
     } 
    } 

    public static void main(String[] args) { 
     System.out.println(new C() { 
      @Override 
      public String toString() { 
       return "I'm anonymous"; 
      } 
     }); 
    } 
} 

risultati in un errore di compilazione:

cannot inherit from final HelloWorld.C 

Perché c un E.VALUE crea una sottoclasse anonima E, sovrascrivendo il metodo toString, mentre l'uso di una classe finale invece di un enum finale implicito genera un errore in fase di compilazione?

In particolare, perché VALUE può sovrascrivere qualsiasi cosa in E? Ho avuto l'impressione che il codice

public enum E { 
    VALUE; 
} 

era o meno equivalente a

public static final class E { 
    public static final E VALUE = new E(); 
} 

nel qual caso la natura anonima non sarebbe stato permesso.

Qual è la differenza? Perché le enumerazioni sono speciali?

+3

Impossibile spiegarne il motivo, ma JLS7 afferma che _L'ente di classe facoltativo di una costante di enum definisce implicitamente una dichiarazione di classe anonima (§15.9.5) che estende il tipo di enum immediatamente racchiuso. L'organismo di classe è governato dalle solite regole delle classi anonime; in particolare non può contenere alcun costruttore. Forse l'intenzione era di dare allo sviluppatore una maggiore flessibilità nel definire le costanti di enum. –

+0

Le enumerazioni sono state progettate in questo modo per servire scopi di programmazione speciali non coperti da questa risposta. – Piovezan

+0

Perché le enumerazioni in Java sono ... speciali. Hai detto rozzamente te stesso. Se qualcuno scrivesse l'idea alla base del ragionamento sarebbe grandioso, naturalmente. +1 ancora per uno snippet interessante. –

risposta

15

Secondo il JLS:

An enum type is implicitly final unless it contains at least one enum constant that has a class body.

Nel tuo esempio, VALUE ha un corpo di classe e quindi E non è implicitamente finale.

Edit: Ecco un rapido esempio che convalida l'affermazione:

import java.lang.reflect.Modifier; 

public class Sandbox { 
    public enum E { 
    VALUE {}; 
    } 

    public enum E2 { 
    VALUE; 
    } 

    public static void main(String[] args) { 
    System.out.println(E.class); 
    System.out.println(E.VALUE.getClass()); 
    System.out.println("E.VALUE is subclass of E = " + E.VALUE.getClass().getSuperclass().equals(E.class)); 
    System.out.println("E modifiers: " + Modifier.toString(E.class.getModifiers())); 
    System.out.println("E2 modifiers: " + Modifier.toString(E2.class.getModifiers())); 
    } 
} 

si può vedere dall'output che il compilatore sta aggiungendo il final modificatore E2 ma non E:

class Sandbox$E 
class Sandbox$E$1 
E.VALUE is subclass of E = true 
E modifiers: public static 
E2 modifiers: public static final 

Modifica n. 2: Anche se E è nonfinal ed è una sottoclasse da VALUE, esplicitamente cercando di estenderlo ad esempio con class Foo extends E o enum Bar extends E è un errore di compilazione in base alle 8.1.4. Superclasses and Subclasses:

It is a compile-time error if the ClassType names the class Enum or any invocation of it.

+0

Ma non è ancora possibile estenderlo, giusto? Quindi, come funziona? – wchargin

+0

Nell'esempio dell'OP, la classe 'VALUE' è una sottoclasse anonima di' E'. 'System.out.println (E.VALUE.getClass())' produrrà qualcosa come 'E $ 1' e' E.VALUE.getClass(). GetSuperclass(). Equals (E.class) == true' – DannyMo

+0

@ WChargin aggiornato con informazioni aggiuntive. Per farla breve: perché il JLS dice così =) – DannyMo

5

Penso che se si confrontano le classi e le enumerazioni, poi l'enum E può essere confrontato con una classe e il valore enum VALUE può essere confrontato con un'istanza anonima.Così, il vostro primo esempio può essere riscritta come segue:

public class Sandbox { 
    public static class E { 
     public static final E VALUE = new E() { 
      @Override 
      public String toString() { 
       return "I'm the value"; 
      } 
     }; 

     @Override 
     public String toString() { 
      return "I'm the enum"; 
     } 
    } 
    public static void main(String[] args) { 
     System.out.println(E.VALUE); 
    } 
} 

+1

+1: hai appena * reinventato * l'enum' in termini di 'class'. –

+0

Mai pensato in questo modo! – vvtx

2

Se si prende in considerazione quanto segue, la vostra preoccupazione può essere ridotto:

Una classe che non ha non -private constructor è efficace finale poiché è impossibile dichiarare la sua sottoclasse al di fuori del suo corpo. È un dettaglio tecnico minore se la classe definita da uno enum è dichiarata final o meno: in entrambi i casi sarà efficacemente finale.

Problemi correlati