¿Cómo puedo conseguir esto?
public class GenericClass<T>
{
public Type getMyType()
{
//How do I return the type of T?
}
}
Todo lo que he intentado hasta ahora siempre devuelve el tipo en Object
lugar del tipo específico utilizado.
java
generics
reflection
Glenn
fuente
fuente
Respuestas:
Como otros mencionaron, solo es posible mediante la reflexión en ciertas circunstancias.
Si realmente necesita el tipo, este es el patrón de solución habitual (seguro de tipo):
fuente
Foo foo1 = GetDao<Foo>(Foo.class).get(Foo.class, 1)
public static <T> GenericClass<T> of(Class<T> type) {...}
y luego llaman como tal:GenericClass<String> var = GenericClass.of(String.class)
. Un poco más amableHe visto algo como esto
en el ejemplo de hibernate GenericDataAccessObjects
fuente
class A implements Comparable<String>
, el parámetro de tipo real esString
, pero NO PUEDE decir que enSet<String> a = new TreeSet<String>()
, el parámetro de tipo real esString
. De hecho, la información del parámetro tipo se "borra" después de la compilación, como se explica en otras respuestas.java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
esta respuesta.Class-Mate
la gente de Jackson. Escribí un resumen(Class<T>) ((ParameterizedType)getClass().getSuperclass().getGenericSuperclass()).getActualTypeArguments()
para llegar a los argumentos de tipo real.Los genéricos no se reifican en tiempo de ejecución. Esto significa que la información no está presente en tiempo de ejecución.
Agregar genéricos a Java mientras se mantenía la compatibilidad con versiones anteriores fue un tour-de-force (puede ver el documento seminal al respecto: Hacer el futuro seguro para el pasado: agregar genérico al lenguaje de programación Java ).
Hay una rica literatura sobre el tema, y algunas personas no están satisfechas con el estado actual, algunos dicen que en realidad es un señuelo y no hay una necesidad real de ello. Puedes leer ambos enlaces, los encontré bastante interesantes.
fuente
Usa guayaba.
Hace un tiempo, publiqué algunos ejemplos de compromiso completo que incluyen clases abstractas y subclases aquí .
Nota: esto requiere que cree una instancia de una subclase de
GenericClass
para que pueda vincular el parámetro de tipo correctamente. De lo contrario, solo devolverá el tipo comoT
.fuente
java.lang.IllegalArgumentException: class com.google.common.reflect.TypeToken isn't parameterized
. Entonces cambié la líneanew TypeToken(getClass()) { }
anew TypeToken<T>(getClass()) { }
. Ahora, el código funciona bien, pero Type sigue siendo 'T'. Vea esto: gist.github.com/m-manu/9cda9d8f9d53bead2035default Type getParameterType() { final TypeToken<T> typeToken = new TypeToken<T>(getClass()) {}; final Type type = typeToken.getType(); return type; }
GenericClass
, debe hacer esa claseabstract
para que el uso incorrecto no se compile.Seguro que puede.
Java no utiliza la información en tiempo de ejecución, por razones de compatibilidad con versiones anteriores. Pero la información en realidad está presente como metadatos y se puede acceder a través de la reflexión (pero todavía no se utiliza para la verificación de tipos).
Desde la API oficial:
http://download.oracle.com/javase/6/docs/api/java/lang/reflect/ParameterizedType.html#getActualTypeArguments%28%29
Sin embargo , para su escenario, no usaría la reflexión. Personalmente, estoy más inclinado a usar eso para el código marco. En su caso, simplemente agregaría el tipo como parámetro de constructor.
fuente
Los genéricos de Java son principalmente tiempo de compilación, esto significa que la información de tipo se pierde en tiempo de ejecución.
será compilado a algo como
Para obtener la información de tipo en tiempo de ejecución, debe agregarla como argumento del ctor.
Ejemplo:
fuente
private final Class<T> type;
Type t = //String[]
fuente
Solía seguir enfoque:
fuente
No creo que pueda, Java utiliza el borrado de tipo al compilar para que su código sea compatible con las aplicaciones y bibliotecas que se crearon pre-genéricos.
De los documentos de Oracle:
http://docs.oracle.com/javase/tutorial/java/generics/erasure.html
fuente
La técnica descrita en este artículo por Ian Robertson funciona para mí.
En resumen, un ejemplo rápido y sucio:
fuente
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
Creo que hay otra solución elegante.
Lo que quiere hacer es (con seguridad) "pasar" el tipo del parámetro de tipo genérico desde la clase concerete a la superclase.
Si te permites pensar en el tipo de clase como "metadatos" en la clase, eso sugiere el método Java para codificar metadatos en tiempo de ejecución: anotaciones.
Primero defina una anotación personalizada a lo largo de estas líneas:
Entonces puede tener que agregar la anotación a su subclase.
Luego puede usar este código para obtener el tipo de clase en su clase base:
Algunas limitaciones de este enfoque son:
PassedGenericType
) en DOS lugares en lugar de uno que no sea SECO.fuente
Esta es mi solución:
fuente
¡Aquí está la solución de trabajo!
NOTAS: Solo se puede usar como superclase
1. Se debe ampliar con la clase escrita (
Child extends Generic<Integer>
)O
2. Se debe crear como implementación anónima (
new Generic<Integer>() {};
)fuente
No puedes Si agrega una variable miembro de tipo T a la clase (ni siquiera tiene que inicializarla), podría usarla para recuperar el tipo.
fuente
Aquí hay una forma, que he tenido que usar una o dos veces:
Junto con
fuente
Una solución simple para esta cabina es la siguiente
fuente
Para completar algunas de las respuestas aquí, tuve que obtener el ParametrizedType de MyGenericClass, sin importar qué tan alta sea la jerarquía, con la ayuda de la recursividad:
fuente
Aquí está mi truco:
fuente
T
es una variable de tipo. En el caso de queT
sea una variable de tipo, los varargs crean una matriz de borrado deT
. Ver, por ejemplo, http://ideone.com/DIPNwd .En caso de que use almacenar una variable usando el tipo genérico, puede resolver fácilmente este problema agregando un método getClassType de la siguiente manera:
Utilizo el objeto de clase proporcionado más adelante para verificar si es una instancia de una clase dada, de la siguiente manera:
fuente
value
es asínull
? En segundo lugar, ¿quévalue
pasa si es una subclase deT
?Constant<Number> c = new Constant<Number>(new Integer(0)); Class<Number> n = c.getClassType();
regresaInteger.class
cuando debería regresarNumber.class
. Sería más correcto regresarClass<? extends T>
.Integer.class
es unClass<? extends Number>
pero no unClass<Number>
.Aqui esta mi solucion
No importa cuántos niveles tenga su jerarquía de clases, esta solución aún funciona, por ejemplo:
En este caso, getMyType () = java.lang.String
fuente
Exception in thread "main" java.lang.NullPointerException at Main$ClassA.findTypeArguments(Main.java:54) at Main$ClassA.findTypeArguments(Main.java:54) at Main$ClassA.findTypeArguments(Main.java:54) at Main$ClassA.<init>(Main.java:43) at Main.main(Main.java:61)
fuente
Aquí está mi solución. Los ejemplos deberían explicarlo. El único requisito es que una subclase debe establecer el tipo genérico, no un objeto.
fuente
Hice lo mismo que @Moesio Above pero en Kotlin podría hacerse de esta manera:
fuente
Puede ser útil para alguien. Puede usar java.lang.ref.WeakReference; de esta manera:
fuente
WeakReference
? Proporcione alguna explicación con su respuesta, no solo un código.SomeClass<MyClass>
, puede crear instanciasSomeClass
y llamargetType
a esa instancia y tener el tiempo de ejecuciónMyClass
.WeakReference
? Lo que dijiste no es diferente de la mayoría de las otras respuestas.AtomicReference
,List
,Set
).Encontré que esta es una solución simple, comprensible y fácil de explicar.
fuente
(T...t)
. (Es por eso que este código no funciona.)