operador - Obteniendo T.class a pesar del borrado de tipos de Java
tipo comodin java (5)
Estoy tratando de vincular una interfaz a su implementación como leída de un archivo de configuración para que pueda alimentarlo a mi contenedor IoC. Aquí está más o menos lo que estoy tratando de hacer:
public class PropertyImplementationBinder<T> {
// ...
public Class getInterfaceClass() {
return T.class; // OR Class<T>, note T is not newable
}
public Class getImplementationClass() {
return /* read config file to get implementation class */;
}
}
¿Es de alguna manera posible obtener T.class
?
Necesitas pasar explícitamente la clase al constructor (y almacenarla tú mismo).
private final Class<T> clazz;
PropertyImplementationBinder(Class<T> clazz){
this.clazz = clazz;
}
public Class<T> getInterfaceClass() {
return clazz;
}
No, no es posible.
La única excepción al borrado de tipos de Java es que a través de la reflexión puede encontrar el tipo parametrizado a través de la reflexión en los campos de una clase.
Puede obtener los argumentos de tipo reales para una superclase genérica de una clase. Esta publicación de blog explora las posibilidades presentadas por este, incluido un pequeño truco usando clases internas anónimas triviales. Para citar directamente:
Resulta que aunque la JVM no rastreará los argumentos de tipo reales para las instancias de una clase genérica, rastrea los argumentos de tipo reales para las subclases de las clases genéricas. En otras palabras, aunque una
new ArrayList<String>()
es realmente unanew ArrayList()
en tiempo de ejecución, si una clase amplíaArrayList<String>
, entonces la JVM sabe queString
es el argumento de tipo real para el parámetro de tipoList
.
Por cierto. El método estático de ejemplo getType en el artículo de @Richard Gomes tiene dos errores. debería ir así:
static public Class<?> getType(final Class<?> klass, final int pos) {
// obtain anonymous, if any, class for ''this'' instance
final Type superclass = klass.getGenericSuperclass();
// test if an anonymous class was employed during the call
if ( !(superclass instanceof ParameterizedType) ) {
throw new RuntimeException("This instance should belong to an anonymous class");
}
// obtain RTTI of all generic parameters
final Type[] types = ((ParameterizedType) superclass).getActualTypeArguments();
// test if enough generic parameters were passed
if ( pos >= types.length ) {
throw new RuntimeException(String.format("Could not find generic parameter #%d because only %d parameters were passed", pos, types.length));
}
if (!(types[pos] instanceof Class<?>)) {
throw new RuntimeException("Generic type is not a class but declaration definition(all you get is /"[T]/") " + types[pos]);
}
// return the type descriptor of the requested generic parameter
return (Class<?>) types[pos];
}
Lamentablemente, todavía no es la bala mágica porque funciona si tienes en código explícitamente
getType(new SomeObject<String>(){}.class, 0) // you get String.class
pero si llamas esto algo así como
getType(new SomeObject<T>(){}.class, 0) // you get T as TypeVariable<D> and not actuall class of it
Solo nombre T.
Contrariamente a lo que es ampliamente aceptado y raramente conocido, se puede evitar el borrado de tipos, lo que significa que los destinatarios tienen la capacidad de saber qué parámetros genéricos se utilizaron durante la llamada.
Por favor, eche un vistazo a: Usando TypeTokens para recuperar parámetros genéricos
El artículo también habla sobre las experiencias de nuestros usuarios con la técnica. En pocas palabras, terminamos cayendo de nuevo al ...
Técnica convencional y ampliamente utilizada: "Pasar tipos de clase en constructores"