reflexion programacion por metodo method jarroba invocar example ejemplos anotaciones java generics reflection

java - programacion - Obtener el tipo genérico de clase en tiempo de ejecución



reflexion java ejemplos (23)

Aquí está la solución de trabajo !!!

@SuppressWarnings("unchecked") private Class<T> getGenericTypeClass() {     try {         String className = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0].getTypeName();         Class<?> clazz = Class.forName(className);         return (Class<T>) clazz;     } catch (Exception e) {         throw new IllegalStateException("Class is not parametrized with generic type!!! Please use extends <> ");     } }

NOTAS: Puede ser usado solo como superclase
1. Tiene que extenderse con la clase escrita (el Child extends Generic<Integer> )
O
2. Debe crearse como implementación anónima ( new Generic<Integer>() {}; )

¿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 Object lugar del tipo específico utilizado.


Aquí está mi solución

public class GenericClass<T> { private Class<T> realType; public GenericClass() { findTypeArguments(getClass()); } private void findTypeArguments(Type t) { if (t instanceof ParameterizedType) { Type[] typeArgs = ((ParameterizedType) t).getActualTypeArguments(); realType = (Class<T>) typeArgs[0]; } else { Class c = (Class) t; findTypeArguments(c.getGenericSuperclass()); } } public Type getMyType() { // How do I return the type of T? (your question) return realType; } }

No importa cuántos niveles tenga su jerarquía de clases, esta solución todavía funciona, por ejemplo:

public class FirstLevelChild<T> extends GenericClass<T> { } public class SecondLevelChild extends FirstLevelChild<String> { }

En este caso, getMyType () = java.lang.String


Aquí está mi truco:

public class Main { public static void main(String[] args) throws Exception { System.out.println(Main.<String> getClazz()); } static <T> Class getClazz(T... param) { return param.getClass().getComponentType(); } }


Aquí hay una forma, que he tenido que usar una o dos veces:

public abstract class GenericClass<T>{ public abstract Class<T> getMyType(); }

Junto con

public class SpecificClass extends GenericClass<String>{ @Override public Class<String> getMyType(){ return String.class; } }


Como han mencionado otros, solo es posible a través de la reflexión en ciertas circunstancias.

Si realmente necesita el tipo, este es el patrón de solución habitual (seguro para el tipo):

public class GenericClass<T> { private final Class<T> type; public GenericClass(Class<T> type) { this.type = type; } public Class<T> getMyType() { return this.type; } }


Creo que hay otra solución elegante.

Lo que desea 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:

import java.lang.annotation.*; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface EntityAnnotation { Class entityClass(); }

Luego puede tener que agregar la anotación a su subclase.

@EntityAnnotation(entityClass = PassedGenericType.class) public class Subclass<PassedGenericType> {...}

Luego puedes usar este código para obtener el tipo de clase en tu clase base:

import org.springframework.core.annotation.AnnotationUtils; . . . private Class getGenericParameterType() { final Class aClass = this.getClass(); EntityAnnotation ne = AnnotationUtils.findAnnotation(aClass, EntityAnnotation.class); return ne.entityClass(); }

Algunas limitaciones de este enfoque son:

  1. Usted especifica el tipo genérico ( PassedGenericType ) en DOS lugares en lugar de uno que no sea DRY.
  2. Esto solo es posible si puedes modificar las subclases concretas.

En caso de que utilice almacenar una variable utilizando el tipo genérico, puede resolver este problema fácilmente agregando un método getClassType de la siguiente manera:

public class Constant<T> { private T value; @SuppressWarnings("unchecked") public Class<T> getClassType () { return ((Class<T>) value.getClass()); } }

Utilizo el objeto de clase proporcionado más adelante para verificar si es una instancia de una clase dada, de la siguiente manera:

Constant<?> constant = ...; if (constant.getClassType().equals(Integer.class)) { Constant<Integer> integerConstant = (Constant<Integer>)constant; Integer value = integerConstant.getValue(); // ... }


Encontré que esta es una solución simple, comprensible y fácilmente explicable.

public class GenericClass<T> { private Class classForT(T...t) { return t.getClass().getComponentType(); } public static void main(String[] args) { GenericClass<String> g = new GenericClass<String>(); System.out.println(g.classForT()); System.out.println(String.class); } }


Esta es mi solución:

import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; public class GenericClass<T extends String> { public static void main(String[] args) { for (TypeVariable typeParam : GenericClass.class.getTypeParameters()) { System.out.println(typeParam.getName()); for (Type bound : typeParam.getBounds()) { System.out.println(bound); } } } }


He visto algo como esto

private Class<T> persistentClass; public Constructor() { this.persistentClass = (Class<T>) ((ParameterizedType) getClass() .getGenericSuperclass()).getActualTypeArguments()[0]; }

en el ejemplo de hibernate GenericDataAccessObjects


La técnica descrita en este artima.com/weblogs/viewpost.jsp?thread=208860 funciona para mí.

En breve ejemplo rápido y sucio:

public abstract class AbstractDAO<T extends EntityInterface, U extends QueryCriteria, V> { /** * Method returns class implementing EntityInterface which was used in class * extending AbstractDAO * * @return Class<T extends EntityInterface> */ public Class<T> returnedClass() { return (Class<T>) getTypeArguments(AbstractDAO.class, getClass()).get(0); } /** * Get the underlying class for a type, or null if the type is a variable * type. * * @param type the type * @return the underlying class */ public static Class<?> getClass(Type type) { if (type instanceof Class) { return (Class) type; } else if (type instanceof ParameterizedType) { return getClass(((ParameterizedType) type).getRawType()); } else if (type instanceof GenericArrayType) { Type componentType = ((GenericArrayType) type).getGenericComponentType(); Class<?> componentClass = getClass(componentType); if (componentClass != null) { return Array.newInstance(componentClass, 0).getClass(); } else { return null; } } else { return null; } } /** * Get the actual type arguments a child class has used to extend a generic * base class. * * @param baseClass the base class * @param childClass the child class * @return a list of the raw classes for the actual type arguments. */ public static <T> List<Class<?>> getTypeArguments( Class<T> baseClass, Class<? extends T> childClass) { Map<Type, Type> resolvedTypes = new HashMap<Type, Type>(); Type type = childClass; // start walking up the inheritance hierarchy until we hit baseClass while (!getClass(type).equals(baseClass)) { if (type instanceof Class) { // there is no useful information for us in raw types, so just keep going. type = ((Class) type).getGenericSuperclass(); } else { ParameterizedType parameterizedType = (ParameterizedType) type; Class<?> rawType = (Class) parameterizedType.getRawType(); Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); TypeVariable<?>[] typeParameters = rawType.getTypeParameters(); for (int i = 0; i < actualTypeArguments.length; i++) { resolvedTypes.put(typeParameters[i], actualTypeArguments[i]); } if (!rawType.equals(baseClass)) { type = rawType.getGenericSuperclass(); } } } // finally, for each actual type argument provided to baseClass, determine (if possible) // the raw class for that type argument. Type[] actualTypeArguments; if (type instanceof Class) { actualTypeArguments = ((Class) type).getTypeParameters(); } else { actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments(); } List<Class<?>> typeArgumentsAsClasses = new ArrayList<Class<?>>(); // resolve types by chasing down type variables. for (Type baseType : actualTypeArguments) { while (resolvedTypes.containsKey(baseType)) { baseType = resolvedTypes.get(baseType); } typeArgumentsAsClasses.add(getClass(baseType)); } return typeArgumentsAsClasses; } }


Los genéricos de Java son en su mayoría tiempo de compilación, esto significa que la información de tipo se pierde en tiempo de ejecución.

class GenericCls<T> { T t; }

será compilado para algo como

class GenericCls { Object o; }

Para obtener la información de tipo en tiempo de ejecución, debe agregarla como un argumento del ctor.

class GenericCls<T> { private Class<T> type; public GenericCls(Class<T> cls) { type= cls; } Class<T> getType(){return type;} }

Ejemplo:

GenericCls<?> instance = new GenericCls<String>(String.class); assert instance.getType() == String.class;


Los genéricos no son reificados 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 era un tour-de-force (puede ver el documento seminal sobre esto: hacer que el futuro sea seguro para el pasado: agregar genéricoidad al lenguaje de programación Java ).

Hay una rica literatura sobre el tema, y ​​algunas personas están dissatisfied con el estado actual, algunas dicen que en realidad es un lure y que no hay una necesidad real de hacerlo. Puedes leer ambos enlaces, me parecieron bastante interesantes.


No creo que puedas, Java utiliza el borrado de tipos al compilar, por lo que tu código es compatible con las aplicaciones y bibliotecas que se crearon de forma pre-generica.

De los documentos de Oracle:

Tipo de borrado

Los genéricos se introdujeron en el lenguaje Java para proporcionar controles de tipo más estrictos en el momento de la compilación y para admitir la programación genérica. Para implementar genéricos, el compilador de Java aplica el borrado de tipo a:

Reemplace todos los parámetros de tipo en los tipos genéricos con sus límites u Objeto si los parámetros de tipo son ilimitados. El bytecode producido, por lo tanto, contiene solo clases, interfaces y métodos ordinarios. Inserte moldes tipo si es necesario para preservar la seguridad del tipo. Genere métodos de puente para preservar el polimorfismo en tipos genéricos extendidos. El borrado de tipos garantiza que no se creen nuevas clases para tipos parametrizados; en consecuencia, los genéricos no incurren en gastos generales de ejecución.

http://docs.oracle.com/javase/tutorial/java/generics/erasure.html


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 recursión:

private Class<T> getGenericTypeClass() { return (Class<T>) (getParametrizedType(getClass())).getActualTypeArguments()[0]; } private static ParameterizedType getParametrizedType(Class clazz){ if(clazz.getSuperclass().equals(MyGenericClass.class)){ // check that we are at the top of the hierarchy return (ParameterizedType) clazz.getGenericSuperclass(); } else { return getParametrizedType(clazz.getSuperclass()); } }


Podría ser útil para alguien. Puedes usar java.lang.ref.WeakReference; de esta manera:

class SomeClass<N>{ WeakReference<N> variableToGetTypeFrom; N getType(){ return variableToGetTypeFrom.get(); } }


Seguro que puede.

Java no usa 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 aún no se utiliza para la comprobació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 constructor.


Una solución simple para esta cabina es como a continuación

public class GenericDemo<T>{ private T type; GenericDemo(T t) { this.type = t; } public String getType() { return this.type.getClass().getName(); } public static void main(String[] args) { GenericDemo<Integer> obj = new GenericDemo<Integer>(5); System.out.println("Type: "+ obj.getType()); } }


Usé el enfoque de seguimiento:

public class A<T> { protected Class<T> clazz; public A() { this.clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; } public Class<T> getClazz() { return clazz; } } public class B extends A<C> { /* ... */ public void anything() { // here I may use getClazz(); } }


Usted no puede Si agrega una variable miembro de tipo T a la clase (ni siquiera tiene que inicializarla), puede usarla para recuperar el tipo.


Utilice guayaba.

import com.google.common.reflect.TypeToken; import java.lang.reflect.Type; public class GenericClass<T> { private final TypeToken<T> typeToken = new TypeToken<T>(getClass()) { }; private final Type type = typeToken.getType(); // or getRawType() to return Class<? super T> public Type getType() { return type; } public static void main(String[] args) { GenericClass<String> example = new GenericClass<String>() { }; System.out.println(example.getType()); // => class java.lang.String } }

Hace un tiempo, publiqué algunos ejemplos completos, incluyendo clases abstractas y subclases here .

Nota: esto requiere que GenericClass una subclase de GenericClass para que pueda enlazar el parámetro de tipo correctamente. De lo contrario, solo devolverá el tipo como T


public abstract class AbstractDao<T> <br> { private final Class<T> persistentClass; public AbstractDao() { this.persistentClass = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()) .getActualTypeArguments()[0]; } }


public static final Class<?> getGenericArgument(final Class<?> clazz) { return (Class<?>) ((ParameterizedType) clazz.getGenericSuperclass()).getActualTypeArguments()[0]; }