2010-06-07 17 views
8

Esto podría ser una pregunta estúpida, pero acabo de ver una pregunta que pregunta how to create a Type variable for a generic type. El consenso parecía ser que debería tener un método ficticio para devolver ese tipo, y luego usar el reflejo para obtenerlo (en este caso, quería Map<String, String>). Algo como esto:Creando objeto de tipo parametrizado usando la clase anónima

public Map<String, String> dummy() { throw new Error(); } 

Type mapStringString = Class.forName("ThisClass").getMethod("dummy").getGenericReturnType(); 

Mi pregunta es, no tener reflejo utilizado mucho, ¿No podrías hacer algo como:

Type mapStringString = new ParameterizedType() { 
    public Type getRawType() { 
     return Map.class; 
    } 

    public Type getOwnerType() { 
     return null; 
    } 

    public Type[] getActualTypeArguments() { 
     return new Type[] { String.class, String.class }; 
    } 
}; 

Que este trabajo? ¿Si no, porque no? Y cuáles son algunos de los peligros/problemas si lo hace (además de ser capaz de volver algún tipo como Integer<String> que obviamente no es posible.

+0

Estoy tratando de hacer lo que permite su propuesta de solución: obtener un tipo parametrizado de una materia prima Tipo y lista de parámetros de tipo suministrados en tiempo de compilación. ¿Encontraste otra forma de hacer esto? – user48956

Respuesta

6

seguro de que podría, y para la mayoría de aplicaciones, probablemente sería suficiente.

Sin embargo, utilizando el primer método, obtienes un objeto más refinado. Digamos por ejemplo que creas un objeto type1 usando el primer método y type2 usando el segundo método. Entonces type1.equals(type2) devolverá verdadero (dado que el primer método devuelve un objeto que implementa correctamente el método equals) pero type2.equals(type1) devolvería false (ya que en el segundo método, no ha reemplazado el método equals, y está usando la implementación desde Object).

El mismo razonamiento se aplica a otros métodos (a veces útiles) como toString, hashCode etc. El segundo método no proporciona implementaciones útiles de estos.

+0

En realidad, la implementación type1 (sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl) de equals parece convertir el parámetro de igual a ParameterizedType y luego usar los métodos de interfaz para comparar las clases, por lo que 'type1.equals (type2)' devolvería true, aunque el opuesto ('type2.equals (type1)') devolvería falso; podrías implementarlos también, pero luego el código se vuelve un poco grueso –

+0

Claro. Puede obtener el mismo resultado en el método 2 que en el método 1, pero requiere más trabajo, como habrá notado. – aioobe

2

En realidad, creo que la forma más simple (== código mínimo) para hacer esto sería una interfaz ficticia que extienda el tipo que le interese y luego getGenericInterfaces()[0] de su clase (use getGenericSuperclass() si le interesa una clase) :

private interface MapStringString extends Map<String, String> {} 
private static ParameterizedType mapStringString(){ 
    return (ParameterizedType) MapStringString.class.getGenericInterfaces()[0]; 
} 

doen't escala bien, aunque, como usted tiene que crear una nueva clase para cada ParameterizedType desea representar. No veo por qué su implementación no funcionaría (a menos que haya reducciones en algún lado), y tiene el atractivo beneficio de que puede hacerla reutilizable.

+0

Si bien esto parece tan "hackoso" como el primer método que di, al menos da mejor aspecto al código donde intentas obtener el tipo (simplemente llamando a la función en lugar de hacer obtener clase, luego obtener el método, luego obtener el tipo de retorno genérico tiempo que desea usarlo). –

5

Si incluye la biblioteca Guava de Google en su proyecto (debería, es genial), use su TypeToken para obtener un tipo. La biblioteca Gson de Google (para interactuar con JSON) tiene un version similar. Ambos se utilizan como esta (para obtener una representación de TypeList<String>:

Type t = new TypeToken<List<String>>(){}.getType(); 

Si no quiere depender de ninguna biblioteca de terceros, aún puede utilizar los tipos anónimos para obtener un genérico concreto tipo con . una línea de código (esta técnica no funciona con interfaces y podría ser más problemático de lo que vale para los tipos abstractos) para obtener una representación de TypeHashMap<String, String>, haga lo siguiente:

Type t = new HashMap<String, String>(){}.getClass().getGenericSuperclass(); 

he comprobado que resulta Type instancia .equals() instancias Type creadas por GsonTypeToken, aunque no hemos verificado lo mismo para la versión Guava de TypeToken, a la que no tengo acceso en este momento.(Guava es una biblioteca de uso más general que es muy útil para todo tipo de cosas, probablemente debería utilizarlo de todos modos.)

+0

Esto todavía requiere que se conozca la lista en tiempo de compilación. En el OP, el tipo sin procesar y los tipos de parámetros no se conocían hasta el tipo de compilación. – user48956

Cuestiones relacionadas