2011-03-10 12 views
17

estoy tratando de hacer lo siguiente:¿Cómo obtengo el valor de un Enum, si no conozco la clase en el momento de la compilación?

Class<?> cls = unknownClass; 
if(cls.isEnum()){ 
    @SuppressWarnings("unchecked") 
    Class<? extends Enum<?>> enumClass = (Class<? extends Enum<?>>) cls; 
    Object val = Enum.valueOf(enumClass, "NAME1"); 
} 

Pero me sale el siguiente error:

Bound mismatch: The generic method valueOf(Class<T>, String) of type Enum<E> is 
not applicable for the arguments (Class<capture#5-of ? extends Enum<?>>, String). 
The inferred type capture#5-of ? extends Enum<?> is not a valid substitute for 
the bounded parameter <T extends Enum<T>> 

Puede alguien decirme lo que estoy haciendo mal?

Respuesta

20

Teniendo en cuenta que el reparto no realmente ser comprobar las cosas, me gustaría ir con la versión totalmente crudo:

if (cls.isEnum()){ 
    @SuppressWarnings("unchecked") 
    Object val = Enum.valueOf(cls, "NAME1"); 
} 

que parece funcionar. Ejemplo completo:

public class Test 
{ 
    enum Foo 
    { 
     BAR, BAZ 
    } 


    public static void main(String[] args) 
    { 
     @SuppressWarnings("rawtypes") 
     Class cls = Foo.class; 

     if (cls.isEnum()) 
     {   
      @SuppressWarnings("unchecked") 
      Object value = Enum.valueOf(cls, "BAR"); 
      System.out.println(value); 
     } 
    } 
} 
+0

que no funciona (o es sólo mi compilador)?:) – dacwe

+0

@dacwe: Bueno, funciona en el compilador * my *, pero no has dicho de qué * manera * no funciona. Mostraré un ejemplo breve pero completo ... –

+0

Ah, lo siento, no compila. 'Clase cls = SomeEnum.class; Objeto val = Enum.valueOf (cls, "NAME1"); 'y obtengo un' Bound mismatch' simular como asker. – dacwe

6

El problema es que usted tiene dos ? y podrían ser diferentes y tienen que ser los mismos.

Usted tiene que usar un no genérica de declarar un tipo genérico como

public static <T extends Enum<T>> T val(Class<T> cls) { 
    if(cls.isEnum()) { // is redundant when the compiler checks this. 
     @SuppressWarnings("unchecked") 
     Class<T> enumClass = (Class<T>) cls; 
     T val = Enum.valueOf(enumClass, "NAME1"); 
     return val; 
    } 
    return null; 
} 

Sin embargo, llamar a este método es un poco de una pesadilla así. ;)

+0

'T 'se define como una clase que extiende' Enum 'Esto se debe a la declaración engorrosa/recursiva de Enum de 'public class Enum >' –

+0

@Peter: sí, pero va a borrarse por completo ya que la persona que llama no puede interactuar con T. –

+0

Como escribió, ¿cómo * do * llamo al método? :) – dacwe

3

Class.getEnumConstants daré todas las enumeraciones, que luego se puede encontrar el que usted está interesado en

código de Modificación de Jon:

public class Test { 
    private enum Foo { 
     BAR, BAZ 
    } 

    public static void main(String[] args) { 
     Class<?> cls = Foo.class; 

     if (cls.isEnum()) { 
      for (Object constant : cls.getEnumConstants()) { 
       Enum<?> enumConstant = (Enum<?>)constant; 
       if (enumConstant.name().equals("BAR")) { 
        System.out.println(constant); 
        break; 
       } 
      } 
     } 
    } 
} 

En Java SE 8, que posiblemente va a ser. capaz de hacer algo inteligente con una lambda y flujo de control abstraído.

Nota:

  • La reflexión es casi siempre una muy mala idea.
  • No hay necesidad de advertencia no controlada o supresión de esas advertencias válidas.
  • No hay necesidad de tipos en bruto (que deletrean y semánticas) advertencia o supresión de esas advertencias válidas.
  • No hay necesidad de una queja infundada.
  • No hay necesidad de rechazar esta respuesta.
+0

Me gusta que, si no conozco el tipo de enumeración en tiempo de compilación, esta solución no genere una advertencia de compilación. Puedo tener solo una instancia de tipo foo y llamar a fooInstance.getClass() y usar eso para cls. – Cameron

1

Usar el tipo sin procesar es bueno. Si bien Java era reacio a agregar el tipo crudo, se ha demostrado que es necesario e indispensable, más allá de los problemas de compatibilidad con versiones anteriores.

Sin tipos crudos, para resolver su problema de una manera teóricamente perfecta, Java tiene que ser mucho más complicado. Probablemente necesite una variable tipo variable. En ese punto, el código ya no es para complacer a los humanos, es para complacer a las máquinas. (Estamos probablemente ya en este punto, teniendo en cuenta todo el código genéricos que son imposibles de entender)

-1
class EnumValues<P extends Enum<P>> 
    { 
     public static <P extends Enum<P>> P [] getValues(Class<P> keyType) 
     { 
      return keyType.getEnumConstants(); 
     } 
    } 

Uso:

Class cls = Thread.State.class; 
    for(Enum en : EnumValues.getValues(cls)) 
     System.out.println(en.name()); 
+0

Llamar a un método genérico con tipos crudos es un poco malo. Efectivamente hay un elenco sin marcar allí. Los compiladores recientes te darán advertencias (¡atención!). (No es mi voto negativo, por cierto). –

Cuestiones relacionadas