2011-01-29 20 views
63

Tengo una lista, programada así: public class MyList<T>. ¿Hay alguna forma de usar la variable T para obtener el nombre de la clase (para que pueda, desde dentro de MyList, saber si T es una cadena, un socket, etc.)?genéricos de Java: ¿clase?

EDITAR: No importa, encontró la respuesta here.

+0

Usted ya sabe la respuesta, pero Puede consultar http://google-guice.googlecode.com/svn/trunk/javadoc/com/google/inject/TypeLiteral.html – maaartinus

Respuesta

89

Respuesta corta: No se puede.

Respuesta larga:

Debido a la forma en que los genéricos se implementa en Java, el tipo genérico T no se mantiene en tiempo de ejecución. Aún así, puede usar un miembro de datos privados:

public class Foo<T> 
{ 
    private Class<T> type; 

    public Foo(Class<T> type) { this.type = type; } 
} 
24

Estás viendo el resultado de Type Erasure. Desde esa página ...

Cuando se crea una instancia de un tipo genérico, el compilador traduce esos tipos por una técnica llamada Tipo de borrado - un proceso donde el compilador elimina toda información relacionada con los parámetros de tipo y el tipo argumentos dentro de una clase o método . La eliminación de tipos habilita las aplicaciones Java que usan genéricos a mantienen la compatibilidad binaria con Se crearon bibliotecas y aplicaciones Java que antes que los genéricos.

Por ejemplo, la caja <cadena> es traducida al tipo de caja, que es del tipo llamado cruda - un tipo de prima es un nombre genérico o clase de interfaz sin ningún argumento de tipo. Esto significa que no puede encontrar qué tipo de objeto está usando una clase genérica en runtime.

Esto también se ve así question que tiene una pretty good answer as well.

3

No estoy 100% seguro de si esto funciona en todos los casos (necesita al menos Java 1.5):

import java.lang.reflect.Field; 
import java.lang.reflect.ParameterizedType; 
import java.lang.reflect.Type; 
import java.util.HashMap; 
import java.util.Map; 

public class Main 
{ 
    public class A 
    { 
    } 

    public class B extends A 
    {  
    } 


    public Map<A, B> map = new HashMap<Main.A, Main.B>(); 

    public static void main(String[] args) 
    { 

     try 
     { 
      Field field = Main.class.getField("map");   
      System.out.println("Field " + field.getName() + " is of type " + field.getType().getSimpleName()); 

      Type genericType = field.getGenericType(); 

      if(genericType instanceof ParameterizedType) 
      { 
       ParameterizedType type = (ParameterizedType) genericType;    
       Type[] typeArguments = type.getActualTypeArguments(); 

       for(Type typeArgument : typeArguments) 
       { 
        Class<?> classType = ((Class<?>)typeArgument);     
        System.out.println("Field " + field.getName() + " has a parameterized type of " + classType.getSimpleName()); 
       } 
      } 
     } 
     catch(Exception e) 
     { 
      e.printStackTrace(); 
     } 
    }  
} 

Esta salida voluntad:

mapa de campo es de tipo Mapa
mapa campo tiene un tipo parametrizado de un mapa de campo
tiene un tipo parametrizado de B

+0

Una vez que traté de hacer algo similar durante la refacturación de General DAO, revisé algunos ejemplos de código similares. No recuerdo por qué, pero decidí no seguir ese enfoque (creo que no funcionó bien en todos los casos, tal vez la jerarquía de clases era obligatoria). Tu ejemplo funciona :) +1 P.S. Algunos tutoriales extendidos que he encontrado: http://www.artima.com/weblogs/viewpost.jsp?thread=208860 –

+0

Encontré el artículo original donde lo saqué (el ejemplo anterior se extrae de uno de nuestros trabajos). proyectos): http://tutorials.jenkov.com/java-reflection/generics.html#fieldtypes El artículo dice que esto solo funciona con campos públicos, pero eso no es cierto, también se puede acceder a campos protegidos y privados a través de la reflexión (solo use getDeclaredField en lugar de getField) – esaj

+1

Esto no responde la pregunta. Esto obtiene el tipo utilizado para declarar un campo. ¿Cómo es esto relevante? – newacct

39

me gusta la solución de

http://www.nautsch.net/2008/10/28/class-von-type-parameter-java-generics/

public class Dada<T> { 

    private Class<T> typeOfT; 

    @SuppressWarnings("unchecked") 
    public Dada() { 
     this.typeOfT = (Class<T>) 
       ((ParameterizedType)getClass() 
       .getGenericSuperclass()) 
       .getActualTypeArguments()[0]; 
    } 
... 
+0

Esta solución funciona bien para mí. La ventaja es que no es necesario pasar parámetros adicionales como otras soluciones mencionadas. Cualquier problema al usar esto? –

+0

sigue funcionando bien – wutzebaer

+11

Esto solo funcionará si la clase de tiempo de ejecución es una subclase directa de la superclase genérica. –