2010-09-01 8 views
6

(Esto es un tanto una continuación de mi previous question)¿Cómo obtener el valor <?> para un objeto Foo <?>?

Tengo un objeto Foo<?>, foo. Foo<T> es una interfaz.

¿Cómo obtener el valor de tipo oculto detrás de <?>?

Tenga en cuenta que esto no es trivial, ya que foo puede ser por ejemplo un objeto de la clase Bar<String>, donde Bar<T> implements Foo<T>, o alguna clase de interfaz anonyomus FloatFoo, donde FloatFoo extends Foo<Float> de ejecución. Necesito una solución que funcione en todos los casos.

Gracias de antemano :)

+0

¿Es Foo su propia interfaz? ¿Puede implementar métodos adicionales? – Arne

+0

Sí, lo pensé - un método 'getType()' resolvería el problema. Probablemente terminaré con una solución como esta. – mik01aj

Respuesta

2

La solución final-final (y tal vez la mejor): refactoré mi código, por lo que no es necesario. Moví todo el código que necesitaba el parámetro de tipo a Foo, por lo que pude proporcionar la implementación adecuada dentro de la clase. Resultó ser mucho menos código.

9

esto no es posible debido a la reflexión de Java utilizando genéricos tiene el problema de Type Erasure. En tiempo de ejecución, se han eliminado los tipos que se han definido para la clase genérica Foo, por lo que al utilizar la reflexión en esa clase no se obtendrá su tipo genérico. Este tipo de información se usa solo en compilación para seguridad de tipo.

C# no tiene este problema y es posible acceder al tipo de clase de una plantilla.

This es una visión general de las diferencias.

8

Bueno, para abreviar, no se puede. Sin embargo, lo que puede hacer es obtener el valor de <?> al usar FloatFoo.

De hecho, por lo que recuerdo, los genéricos no se guardan en la información de la clase.

Sin embargo, cuando crea un subtipo (ya sea clase o interfaz) de un tipo genérico, la información genérica debe ser memorizada ya que puede definir algunos de los métodos de la firma del subtipo.

A modo de ejemplo, si sus Foo interfaceis declaradas como:

public interface Foo<T> { 
    public T doIt(); 
} 

Tener un

public interface FloatFoo extends Foo<Float> 

implica esta interfaz tiene un método

public Float doIt(); 

declarado.

Para eso, el compilador debe tener la información del tipo. Y esta información se reflejará en la API de reflexión por el hecho de que la superclase FloatFoo tendrá algunos parámetros de Tipo asociados a ella. O al menos es lo que recuerdo de los pocos casos que encontré tales casos (o los elaboré, ya que a veces puede ser obligatorio)

Pero obtendrá mucha más información completa en Angelika's generics FAQ.

+0

el problema es que 'getMethod (" doIt "). GetReturnType()' devuelve 'Object', y si ejecutas el método para ver qué devuelve, a veces obtendrías un objeto de subclase, y algunas veces' null'. – mik01aj

+3

relacionado y tal vez útil: http://www.artima.com/weblogs/viewpost.jsp?thread=208860 – Arne

+0

@ m01 El truco de la interfaz que Riduidel menciona no siempre funciona. Se mencionó como un ejemplo de algunos datos que están presentes, pero el problema subyacente aún existe. El enlace mencionado por Arne hace referencia a una solución creada por Neal Gaffer, uno de los desarrolladores de compiladores de Java. – linuxuser27

1

que terminó con la creación de un método getType() en la interfaz:

Class<T> getType(); 

tal vez no es la solución más elegante, pero sin duda la más simple.

+1

Esto todavía no funciona si su es, digamos, Lista . Lo mejor que podrías devolver es List.class. Si la situación llega a ese complejo, eche un vistazo al patrón "Super Type Token": http://gafter.blogspot.com/2006/12/super-type-tokens.html –

Cuestiones relacionadas