如何确定泛型类?

时间:2008-10-08 13:07:34

标签: java generics

我正在创建一个泛型类,并且在其中一个方法中我需要知道当前使用的泛型类的Class。原因是我调用的方法之一将此作为参数。

示例:

public class MyGenericClass<T> {
  public void doSomething() {
    // Snip...
    // Call to a 3rd party lib
    T bean = (T)someObject.create(T.class);
    // Snip...
  }
}

显然,上面的示例不起作用并导致以下错误:类型参数T的非法类文字。

我的问题是:有人知道一个很好的选择或解决方法吗?

7 个答案:

答案 0 :(得分:47)

仍然存在同样的问题:通用信息在运行时被擦除,无法恢复。解决方法是在静态方法的参数中传递类T:

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();
    }
}

这很难看,但确实有效。

答案 1 :(得分:22)

我刚刚指出了这个解决方案:

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];
    }
}

如果A由子类赋予具体类型,则此方法有效:

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

答案 2 :(得分:4)

不幸的是,Christoph的书面解决方案仅适用于非常有限的情况。 [编辑:如下面评论我不再记得我对这句话的推理并且可能是错误的:“请注意,这只会在抽象类中起作用,首先。”]下一个难点是g()只能起作用来自A的DIRECT子类。不过我们可以解决这个问题:

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);
}

这在实践中会在许多情况下起作用,但不是一直都有效。考虑:

public class Foo<U,T extends Collection<?>> extends A<T> {}

(new Foo<String,List<Object>>() {}).g();

这将抛出ClassCastException,因为此处的类型参数根本不是ClassParameterizedType;这是TypeVariable T。所以现在你会被困在试图找出T应该代表什么类型的东西,以及兔子洞等等。

我认为唯一合理的,一般的答案类似于Nicolas的初始答案 - 一般来说,如果你的类需要实例化编译时未知的其他类的对象,那么你的类的用户需要传递明确的类文字(或者,也许是工厂),而不仅仅依赖于泛型。

答案 3 :(得分:2)

我找到另一种方法来获取通用对象的类

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;
  }

答案 4 :(得分:0)

可以使用TypeTools

轻松解决T.
Class<T> t = (Class<T>) TypeResolver.resolveRawArguments(
                                MyGenericClass.class, getClass());

答案 5 :(得分:0)

我将详细阐述Christoph的解决方案。

这是ClassGetter抽象类:

private abstract class ClassGetter<T> {
    public final Class<T> get() {
        final ParameterizedType superclass = (ParameterizedType)
            getClass().getGenericSuperclass();
        return (Class<T>)superclass.getActualTypeArguments()[0];
    }
}

这是一个静态方法,它使用上面的类来查找泛型类&#39;类型:

public static <T> Class<T> getGenericClass() {
    return new ClassGetter<T>() {}.get();
}

作为它的用法示例,您可以使用此方法:

public static final <T> T instantiate() {
    final Class<T> clazz = getGenericClass();
    try {
        return clazz.getConstructor((Class[])null).newInstance(null);
    } catch (Exception e) {
        return null;
    }
}

然后像这样使用它:

T var = instantiate();

答案 6 :(得分:-1)

公共类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);    

}

}