2010-01-22 14 views
6

que estoy tratando de hacer algo a lo largo de las líneas de:Java: conversión de tipo dinámico utilizando las enumeraciones

public void setContents(Object[] values) 
{ 
    ... 

     //A. this works 
     mRank = 
      ((String)(values[Columns.RANK.index])); 

     //B. doesn't work (entire line underlined by netbeans) 
     mRank = 
      (Columns.RANK.type.cast(values[Columns.RANK.index])); 
     //incompatible types: required java,lang.String found: java.lang.Object 

     //C. doesn't work (first RANK is underlined by netbeans) 
     mRank = 
      ((Columns.RANK.type)(values[Columns.RANK.index])); 
     //cannot find symbol symbol: class RANK location: blah.blah.Columns 

    ... 
} 

donde las columnas es una enumeración interior, así:

public static enum Columns 
{ 

    RANK(0, "Rank", String.class), 
    NUMBER(1, "Number", Integer.class); 

    public String text; 
    public Class type; 
    public int index; 

    private Columns(int idx, String text, Class clasz) 
    { 
     this.type = clasz; 
     this.text = text; 
     this.index = idx; 
    } 
} 

entiendo por qué la línea B no funciona, pero lo que no entiendo es por qué C no funciona. Si utilizo Columns.RANK.type en cualquier otro lugar que no sea un tipo de conversión, funciona bien, pero intento hacer un tipo de transmisión con la clase, compila diciendo que no puede encontrar RANK en la enumeración, que no debería ser el caso.

¿Cómo funciona?

Gracias!

+0

'javac' en JDK7 dará una advertencia de pelusas en los tipos en su tipo' Clase 'sin procesar, lo que debería hacer que este tipo de problema sea más obvio. –

Respuesta

4

C no funciona, porque Columns.RANK.type no es accesible en tiempo de compilación.

Sin embargo, B se puede implementar utilizando una clase basada genérico-personalizada en lugar de enum:

class Columns<T> 
{ 
    public static final Columns<String> RANK = new Columns<String>(0, "Rank", String.class); 
    public static final Columns<Integer> NUMBER = new Columns<Integer>(1, "Number", Integer.class); 

    public final Class<T> type; 
    public final String text; 
    public final int index; 

    private Columns(int idx, String text, Class<T> clasz) 
    { 
     this.type = clasz; 
     this.text = text; 
     this.index = idx; 
    } 
} 
+0

@axtavt, excelente solución! Todavía estoy esperando otro para ver si realmente es posible lograr esto usando un 'enum', de lo contrario, la señal va hacia ti. – bguiz

+0

@axtavt, solo FYI, la clase 'Columnas ' debe declararse como 'pública clase estática Columna ', para que funcione como se sugiere - las clases internas no pueden tener miembros estáticos a menos que ellos mismos sean estáticos. – bguiz

0

Como se hace referencia a un class literal, la expresión Columns.RANK.type es de tipo Class<String>. No es un ReferenceType, requerido por un cast expression.

Adición: El compilador piensa que quiso hacer referencia a una clase inexistente llamada RANK que está anidada en Columns.

2

La respuesta corta es que no hay una buena manera de hacer esto con una enumeración. La respuesta de axtavt es probablemente tu mejor opción. trashgod básicamente tiene razón acerca de por qué C no funciona, pero quizás podría necesitar un poco más de explicación.

Debe pensar en cómo el compilador interpreta C. Lo importante aquí es la distinción entre String y String.class. Tienes una expresión de lanzamiento como (String)foo. En una expresión de este tipo, el tipo al que está enviando (en ese ejemplo, String) tiene que ser el nombre de un tipo. No escribiría (String.class)foo, porque no hay una clase llamada String.class. (En cambio, String.class es sólo un objeto, una instancia de java.lang.Class que refleja el tipo String.)

Por lo tanto, cuando el compilador ve (Columns.RANK.type)(values[Columns.RANK.index]), dice "ah, esto es una expresión de fundición. Por lo tanto, el bit de parens en el comienzo debe ser el nombre del tipo que bguiz quiere convertir ". Luego se apaga diligentemente y busca un tipo llamado Columns.RANK.type. Como es el nombre de un tipo, espera que tenga el formato my.package.containing.a.Type.AndMaybe.SomeInnerTypes. Por lo tanto, se divide alrededor de . s, encuentra el tipo Columns, y luego se apaga y busca un tipo interno llamado RANK en Columns. No existe ese tipo interno (la constante RANK no cuenta), por lo que falla con el error que citó.

(Si lo encuentra, continuará buscando otro tipo interno llamado type, y de nuevo, el campo enum no contará.)

Recuerde que el compilador solo sigue un montón de reglas tontas. No importa que también tenga una constante RANK en su enumeración Columns. Tampoco sabe que los nombres de tipos suelen ser mayúsculas. Como resultado, sus mensajes de error a veces son difíciles de interpretar para un humano que está llevando a cabo todo ese contexto en su cabeza. :)

+0

+1: Muy buena explicación de por qué el compilador está escupiendo el error que es. – bguiz

Cuestiones relacionadas