programación - libro de programacion en java netbeans pdf
¿Cómo determinar la clase de un tipo genérico? (7)
Desafortunadamente, la solución de Christoph tal como está escrita solo funciona en circunstancias muy limitadas. [EDITAR: como se comenta a continuación, ya no recuerdo mi razonamiento para esta frase y es probable que esté equivocado: "Tenga en cuenta que esto solo funcionará en clases abstractas, en primer lugar."] La siguiente dificultad es que g()
solo funciona desde DIRECT subclases de A
Podemos arreglar eso, sin embargo:
private Class<?> extractClassFromType(Type t) throws ClassCastException {
if (t instanceof Class<?>) {
return (Class<?>)t;
}
return (Class<?>)((ParameterizedType)t).getRawType();
}
public Class<B> g() throws ClassCastException {
Class<?> superClass = getClass(); // initial value
Type superType;
do {
superType = superClass.getGenericSuperclass();
superClass = extractClassFromType(superType);
} while (! (superClass.equals(A.class)));
Type actualArg = ((ParameterizedType)superType).getActualTypeArguments()[0];
return (Class<B>)extractClassFromType(actualArg);
}
Esto funcionará en muchas situaciones en la práctica, pero no TODO el tiempo. Considerar:
public class Foo<U,T extends Collection<?>> extends A<T> {}
(new Foo<String,List<Object>>() {}).g();
Esto lanzará una ClassCastException
, porque el argumento de tipo aquí no es una Class
o un tipo ParameterizedType
en absoluto; es el TypeVariable
T
Así que ahora estarías atrapado tratando de descubrir qué tipo de T
supuestamente representa, y así sucesivamente en el agujero del conejo.
Creo que la única respuesta razonable y general es algo parecido a la respuesta inicial de Nicolas: en general, si tu clase necesita instanciar objetos de otra clase desconocida en tiempo de compilación, los usuarios de tu clase deben pasar esa clase literal ( o, tal vez, una fábrica) a su clase de forma explícita y no depender únicamente de los genéricos.
Estoy creando una clase genérica y en uno de los métodos necesito saber la Clase del tipo genérico actualmente en uso. La razón es que uno de los métodos que llamo espera esto como un argumento.
Ejemplo:
public class MyGenericClass<T> {
public void doSomething() {
// Snip...
// Call to a 3rd party lib
T bean = (T)someObject.create(T.class);
// Snip...
}
}
Claramente, el ejemplo anterior no funciona y da como resultado el siguiente error: literal de clase ilegal para el parámetro de tipo T.
Mi pregunta es: ¿alguien sabe una buena alternativa o solución alternativa para esto?
Elaboraré la solución de Christoph.
Aquí está la clase abstracta de ClassGetter:
private abstract class ClassGetter<T> {
public final Class<T> get() {
final ParameterizedType superclass = (ParameterizedType)
getClass().getGenericSuperclass();
return (Class<T>)superclass.getActualTypeArguments()[0];
}
}
Aquí hay un método estático que usa la clase anterior para encontrar un tipo de clase genérico:
public static <T> Class<T> getGenericClass() {
return new ClassGetter<T>() {}.get();
}
Como un ejemplo de su uso, puedes hacer este método:
public static final <T> T instantiate() {
final Class<T> clazz = getGenericClass();
try {
return clazz.getConstructor((Class[])null).newInstance(null);
} catch (Exception e) {
return null;
}
}
Y luego úsalo así:
T var = instantiate();
Me acaba de señalar a esta solución:
import java.lang.reflect.ParameterizedType;
public abstract class A<B> {
public Class<B> g() throws Exception {
ParameterizedType superclass =
(ParameterizedType) getClass().getGenericSuperclass();
return (Class<B>) superclass.getActualTypeArguments()[0];
}
}
Esto funciona si a A
se le asigna un tipo concreto por una subclase:
new A<String>() {}.g() // this will work
class B extends A<String> {}
new B().g() // this will work
class C<T> extends A<T> {}
new C<String>().g() // this will NOT work
Siguen los mismos problemas: las informaciones genéricas se borran en el tiempo de ejecución, no se pueden recuperar. Una solución es pasar la clase T en el parámetro de un método estático:
public class MyGenericClass<T> {
private final Class<T> clazz;
public static <U> MyGenericClass<U> createMyGeneric(Class<U> clazz) {
return new MyGenericClass<U>(clazz);
}
protected MyGenericClass(Class<T> clazz) {
this.clazz = clazz;
}
public void doSomething() {
T instance = clazz.newInstance();
}
}
Es feo, pero funciona.
T se puede resolver fácilmente usando TypeTools :
Class<T> t = (Class<T>) TypeResolver.resolveRawArguments(
MyGenericClass.class, getClass());
clase pública DatabaseAccessUtil {
EntityManagerFactory entitymanagerfactory;
EntityManager entitymanager;
public DatabaseAccessUtil() {
entitymanagerfactory=Persistence.createEntityManagerFactory("bookmyshow");
entitymanager=entitymanagerfactory.createEntityManager();
}
public void save (T t) {
entitymanager.getTransaction().begin();
entitymanager.persist(t);
entitymanager.getTransaction().commit();
}
public void update(T t) {
entitymanager.getTransaction().begin();
entitymanager.persist(t);
entitymanager.getTransaction().commit();
}
public void delete(T t) {
entitymanager.getTransaction().begin();
entitymanager.remove(t);
entitymanager.getTransaction().commit();
}
public Object retrieve(Query query) {
return query.getSingleResult();
}
//call the method - retrieve(object,requiredclass.class)
public Object retrieve(Object primaryKey,class clazz) throws Exception {
return entitymanager.find(clazz,primaryKey);
}
}
encuentro otra forma de obtener la Clase del objeto genérico
public Class<?> getGenericClass(){
Class<?> result =null;
Type type =this.getClass().getGenericSuperclass();
if(type instanceofParameterizedType){
ParameterizedType pt =(ParameterizedType) type;
Type[] fieldArgTypes = pt.getActualTypeArguments();
result =(Class<?>) fieldArgTypes[0];
}
return result;
}