2011-04-23 13 views
19
ParameterizedType parameterized = 
    (ParameterizedType) List.class.getMethod("iterator").getGenericReturnType(); 
Type raw = parameterized.getRawType(); 

ParameterizedType#getRawType() devuelve un Type, no un Class<?> (aunque entiendo que ahora implementa java.lang.ClassType). ¿Hay una buena razón por la cual getRawType() no declara que su tipo de devolución es Class<?>? ¿Hay casos extremos en los que el resultado de getRawType() no sea Class<?>?ParameterizedType.getRawType() devuelve j.l.r.Type, no Clase <?>?

Ya es bastante complicado trabajar con j.l.r.Type tal como está; esto parece una instancia en la que podrían habernos ahorrado uno abatido.

+0

Este hilo http://www.velocityreviews.com/forums/t524488-raw-type-other-than-a-class-possible.html indica que el tipo de devolución es siempre una clase, pero también estoy buscando más opiniones sobre esto. –

+0

Parece una separación básica de interfaz e implementación para mí. El Javadoc lista 'Class' como la única implementación de' Type', pero el JRE contiene un par de docenas de clases protegidas que implementan 'Type' también. – skaffman

+1

Compraría la separación de la interfaz frente al argumento de implementación si 'Type' no fuera una interfaz de marcador. Para hacer las cosas que me gustaría hacer con un 'Tipo', debo probar si es una 'Clase ', 'ParameterizedType',' WildcardType', 'GenericArrayType', y tal. Si pudiera lograr lo que quería con un objeto arbitrario solo como un 'Tipo', no me importaría mucho si la clase de tiempo de ejecución del resultado era 'java.lang.Class', o lo que sea. – pholser

Respuesta

13

Debe devolver un objeto Class, no hay otra manera.

¿Por qué? Quién sabe, tal vez algún sesgo idealista. Si devolviera Class, sería la única apariencia de Class en las nuevas interfaces Type.

El problema real es la mezcla de Class y Type. Anteriormente, todos los tipos están representados en Class. Ya estaba desordenado, pero aún tolerable. No había muchos tipos.

Con los nuevos tipos genéricos, deberían haber diseñado una jerarquía Type limpia y fiel a la especificación independiente de Class. En su lugar, incorporaron Class con Type y crearon más desorden. Toda la jerarquía simplemente no tiene sentido. Cualquier persona nueva en el tema y desconocedora de la historia quedará consternada por estas tonterías.

No me gustaría mantener el diseño de Type a un alto nivel. Por ejemplo, ParameterizedType define equals(), pero no hashCode(). No hay forma de que dos implementaciones de ParameterizedType funcionen en un mapa hash. Y el comodín es también un tipo? Diablos no

Y el nombre del método getRawType() es simplemente idiota. No tiene nada que ver con raw type. Debe llamarse claramente getClassOrInterface(). ¿Sería demasiado detallado? Mire getActualTypeArguments() y luego. (Y sí, devuelve argumentos reales! No falsos!)

+0

'ParameterizedType' es solo una interfaz, y no define' equals() 'o' hashCode() '. 'sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl' parece definir ambos, al menos en Sun JRE 1.5.0_22. Siempre puede convertir los 'ParameterizedTypeImpl's que obtiene de la reflexión a su propia implementación de' ParameterizedType' si no se comportan como usted desea. – Andy

3

La implementación de Sun de ParameterizedType ha definido el método getRawType() para devolver Class<?>. Por lo tanto, devuelve claramente solo Class<?>

Sin embargo, en mi classpath hay algunas implementaciones más de ParameterizedType - desde hibernate-validator, desde aspectj, hibernate-annotations, jaxb. Algunos de ellos devuelven Class<?>, algunos - Type. Sin embargo, no sé cómo se usan.

+0

¿eh? Devuelve un 'Tipo' http://download.oracle.com/javase/6/docs/api/java/lang/reflect/ParameterizedType.html#getRawType() ** edit ** ok, que solo implementa' clase' . –

+1

Dije la implementación. 'sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl' – Bozho

+0

Lo extraño es' ParameterizedTypeImpl.getOwnerType() 'devuelve un' Type'! – Andy

2

Estaba pensando en esto, y tengo una corazonada. Tal vez querían dejar abierta la posibilidad de un futuro locura como esta:

public class Z<L extends List<?>> { 
    L<Double> test; 
} 

Esto no es un código legal de Java, pero creo que está claro lo que significaría; new Z<ArrayList<?>>().test sería del tipo ArrayList<Double>.

Si esto fuera legal, ((ParameterizedType) test.getGenericType()).getRawType() devolvería un TypeVariable.

1

Existen otros usos para la jerarquía de interfaz Tipo que solo la API de reflexión. Por ejemplo, una biblioteca de generación de código puede definir implementaciones personalizadas. El JDK 8 en sí tiene 3 implementaciones diferentes de WildcardType. Si ParameterizedType.getRawType() devolvió una instancia de clase, entonces necesitaría poder crear una instancia de clase siempre que lo desee.

Una clase es un tipo muy arraigado en la JVM que tiene enlaces a la memoria administrada nativamente. Para crear una instancia de Clase, debe tener el código de bytes que define la clase. Pero en el caso de una biblioteca de generación de código, el código de bytes aún no existe. Si hubieran exigido que ParameterizedType devolviera una clase, limitaría la aplicabilidad de la jerarquía de la interfaz Tipo solo a la API de reflexión.

Esto puede no parecer un gran problema, pero tampoco es un elenco.

ParameterizedType.getOwnerType() devuelve un tipo ya que puede ser una clase u otro tipo parametrizado. Puede que, en teoría, devolver un TypeVariable, ya que el siguiente es válido de Java:

<M extends Map<?,?>> M.Entry<?,?> first(M map) { ... } 

Sin embargo, es compilado como una referencia estática para el borrado de la variable tipo, en este caso M.Entry se compila como Map.Entry. En lugar de TypeVariable, una llamada a getOwnerType() desde la API de reflexión será una clase, al menos de acuerdo con mis pruebas.

Cuestiones relacionadas