2012-09-20 10 views
7

Quiero definir un tipo de enumeración con dos constantes cuyo "valor" sea el mismo. Llamo a estas dos constantes como duplicadas. Consideremos el siguiente ejemplo: quiero definir una lista de los tipos de navegador, y quiero tener tanto un literal "IE" y "InternetExplorer", de la siguiente manera:¿Cómo puedo definir constantes de enumeración duplicadas en Java?

enum Browser { 
    CHROME("chrome"), 
    FIREFOX("firefox"), 
    IE("ie"), 
    INTERNETEXPLORER("ie"); 

    String type; 
    Browser(String type) { 
     this.type = type; 
    } 
} 

Sin embargo, con esto, el siguiente código fallan,

Browser a = Browser.IE; 
Browser b = Browser.INTERNETEXPLORER; 
Assert.assertTrue(a==b); 

la única solución que se me ocurre es que para añadir un método del tipo Browser que devuelve el valor interno de la instancia del navegador value(). Y el código de prueba de igualdad sería

Assert.assertTrue(a.value()==b.value()) 

Esto no es bueno. Entonces, ¿alguien tiene una mejor idea?

¿Por qué Java no permite sobrescribir los métodos como equals() de la clase Enum<T>?

EDITAR:

OK, gracias por las respuestas y comentarios. Estoy de acuerdo en que mi pensamiento original era contrario al propósito de enum. Creo que los siguientes cambios pueden satisfacer mi necesidad.

public enum Browser { 
    CHROME, 
    FIREFOX, 
    IE; 

    public static Browser valueOfType(String type) { 
     if (b == null) { 
      throw new IllegalArgumentException("No browser of type " + type); 
     switch (type.toLowerCase()) { 
      case "chrome": 
       return Browser.CHROME; 
      case "firefox": 
       return Browser.FIREFOX; 
      case "ie": 
      case "internetexplorer": 
      case "msie": 
       return Browser.IE; 
      default: 
       throw new IllegalArgumentException("No browser of type " + type); 
     } 
    } 
} 
+6

No estoy seguro, entiendo por qué quiere 2 constantes enum 'IE' y' INTERNET_EXPLORER' si son iguales. ¿Puedes explicar por qué lo necesitas? – assylias

+2

el propósito de la enumeración es crear un conjunto de vocabularios controlados que se utiliza para catagorizar o agrupar el mismo concepto. lo que estás haciendo solo rompe su propósito. – gigadot

+0

@assylias, lo necesito porque, en algún lugar diferente, es posible que desee utilizar identificadores diferentes que apunten a lo mismo. Tal vez otro ejemplo tenga más sentido cuando a veces quiero usar ZERO y, a veces, quiero usar NULL, pero quiero que tengan el mismo significado. –

Respuesta

6

Cada enum extiende mutuamente la clase Enum que define equals() como final. Esto se hace porque enum no es una clase regular. JVM garantiza que cada elemento enum sea único, es decir, existe solo una instancia de cada elemento dentro de una JVM.

Esto es necesario por ejemplo para el uso de las enumeraciones en switch comunicado etc.

Lo que estamos tratando de hacer es ir en contra de este concepto: usted quiere tener 2 miembros iguales de la misma enumeración.

Sin embargo, puedo ofrecerle otra solución: defina solo un miembro IE. Definir String[] miembro en la enumeración y el método que se puede encontrar por ningún miembro apropiado alias:

public enum Browser { 


    CHROME("Chrome"), 
    FIREFOX("FireFox"), 
    IE("IE", "MSIE", "Microsoft Internet Exporer"), 
    ; 

    private String[] aliases; 

    private static Map<String, Browser> browsers = new HashMap<>(); 
    static { 
     for (Browser b : Browser.values()) { 
      for (String alias : b.aliases) { 
       browsers.put(alias, b); 
      } 
     } 
    } 

    private Browser(String ... aliases) { 
     this.aliases = aliases; 
    } 

    public static Browser valueOfByAlias(String alias) { 
     Browser b = browsers.get(alias); 
     if (b == null) { 
      throw new IllegalArgumentException(
        "No enum alias " + Browser.class.getCanonicalName() + "." + alias); 
     } 
     return b; 
    } 
} 
-2

me quite el valor de cadena y la instancia de IE duplicado, su no sirve de nada ...

enum Browser { 
    CHROME, 
    FIREFOX, 
    IE 

Si debe tener representación en minúsculas simplemente convertir de nombre de enumeración cuando lo necesite.

+1

Eso realmente no responde a la pregunta ... – assylias

1

No se puede reemplazar el método equals() de una enumeración, pero incluso si se pudiera == el operador no se ejecuta el método equals(): no hay manera de hacer a == b ser true por su ejemplo.

Lo más cerca que puedo pensar es un método de utilidad (estática):

enum Browser { 
    CHROME("chrome"), 
    FIREFOX("firefox"), 
    IE("ie"), 
    INTERNETEXPLORER("ie"); 

    private final String type; 
    Browser(String type) { 
     this.type = type; 
    } 

    public String getType() { 
     return type; 
    } 

    public static boolean equals(Browser b1, Browser b2) { 
     return b1.type.equals(b2.type); 
    } 
} 

También tenga en cuenta que haría typeprivate final. Como es, usted puede hacer esto:

IE.type = "netscape"; // would be allowed 
0

Lo que realmente debe hacer es normalizar la conversión de la entrada a la enumeración, es decir, si su entrada (de almacenamiento de usuario/datos) es IE/Internetexplorer, que debe resolverse a Browser.IE. Eso eliminaría una gran cantidad de verificaciones redundantes en el código para ver si la enumeración es IE o INTERNETEXPLORER.

5

enumeración jerárquica truco es, probablemente, lo que quiere en este caso. Aunque no resuelve el problema de comparación, proporciona una muy buena alternativa para su problema.

http://java.dzone.com/articles/enum-tricks-hierarchical-data

cito los códigos desde el sitio anterior directamente con una ligera simplificación:

public enum OsType { 
    OS(null), 
     Windows(OS), 
      WindowsNT(Windows), 
       WindowsNTWorkstation(WindowsNT), 
       WindowsNTServer(WindowsNT), 
      WindowsXp(Windows), 
      WindowsVista(Windows), 
      Windows7(Windows), 
     Unix(OS), 
      Linux(Unix), 
    ; 
    private OsType parent = null; 

    private OsType(OsType parent) { 
     this.parent = parent; 
    } 
} 
+0

Aunque en mi humilde opinión, esta solución no ayuda a resolver el problema de OP I estoy votando porque se refiere a mi artículo. :) – AlexR

0

como está escrito en Enum Clase

pero extendiéndose esta clase no hace una clase tipo de enumeración, ya que el compilador necesita generar información especial para él.

Con el fin de apoyar la igualdad basada en la referencia equals el método es final.

Puede usar EnumSet para crear EnumSet de enumeraciones relacionadas y luego puede usar el método contains.

public static EnumSet<Browser> MSE = EnumSet.of(Browser.IE, 
    Browser.INTERNETEXPLORER); 

Así su código se verá más abajo.

public enum Browser { 
CHROME("chrome"), FIREFOX("firefox"), IE("ie"), INTERNETEXPLORER("ie"); 

String type; 

Browser(String type) { 
    this.type = type; 
} 

public static EnumSet<Browser> MSE = EnumSet.of(Browser.IE, 
     Browser.INTERNETEXPLORER); 

public static void main(String[] args) { 
    System.out.println(MSE.contains(Browser.IE));//true 
    System.out.println(MSE.contains(Browser.INTERNETEXPLORER));//true 
} 
} 
7

Una forma simple de hacer esto es poner variables de instancia dentro de su clase enum.

enum Browser { 
    CHROME, 
    FIREFOX, 
    INTERNETEXPLORER; 
    public static final Browser IE=INTERNETEXPLORER; 
} 

Entonces, IE sólo debe actuar como un alias para INTERNETEXPLORER, y se puede utilizar de forma indistinta.

EDITAR: Gracias a big_m por sugerir hacer IE final!

EDIT2: Este truco debería funcionar en la mayoría del código, pero hay una excepción si está usando switch/case. Aquí hay un ejemplo:

Browser b; 
switch(b){ 
    case Browser.CHROME: 
     //code for chrome 
     break; 
    case Browser.IE: // <---- SYNTAX ERROR, use Browser.INTERNETEXPLORER in this case 
     //code for internet explorer 
     break; 
} 
+2

¡Gran solución! Sin embargo, lo convertiría en "estático final", por lo que no se puede cambiar. –

Cuestiones relacionadas