获取抽象超类的genericstypes参数的实际types

我有一个类像:

public abstract class BaseDao<T extends PersistentObject> { protected Class<T> getClazz() { return T.class; } // ... } 

但编译器对T.class;T.class;Illegal class literal for the type parameter T

我怎样才能得到T的课?

Class#getGenericSuperclass()提取它是完全可能的,因为它在运行时没有被定义,但是在FooDao extends BaseDao<Foo>编译期间FooDao extends BaseDao<Foo>

下面是一个启发式的例子,如何在抽象类的构造函数中提取所需的generics超types,并考虑子类的层次结构(以及将其应用于genericsEntityManager方法的真实世界用例,而不需要显式提供types):

 public abstract class BaseDao<E extends BaseEntity> { @PersistenceContext private EntityManager em; private Class<E> type; @SuppressWarnings("unchecked") // For the cast on Class<E>. public BaseDao() { Type type = getClass().getGenericSuperclass(); while (!(type instanceof ParameterizedType) || ((ParameterizedType) type).getRawType() != BaseDao.class) { if (type instanceof ParameterizedType) { type = ((Class<?>) ((ParameterizedType) type).getRawType()).getGenericSuperclass(); } else { type = ((Class<?>) type).getGenericSuperclass(); } } this.type = (Class<E>) ((ParameterizedType) type).getActualTypeArguments()[0]; } public E find(Long id) { return em.find(type, id); } public List<E> list() { return em.createQuery(String.format("SELECT e FROM %se ORDER BY id", type.getSimpleName()), type).getResultList(); } // ... } 

其实这并不像看起来那么简单。 如果您有丰富的types层次结构,并且想要获取超types的generics参数,则会出现问题。 例如,您可能具有以下层次结构:

 public abstract class BaseDao<T extends BaseEntity> { ... } public abstract class SpecialDao<X extends SomeType, E extends BaseEntity> extends BaseDao<E> { ... } public class MyDao extends SpecialDao<TypeImpl, EntityImpl> { ... } 

MyDao的实例中调用getClass().getGenericSuperclass()返回SpecialDao<TypeImpl, EntityImpl> ,但是当您在BaseDao方法中调用它时,您不知道generics层次结构有多深。 此外,据我所知,你不能获得超types的通用超types。 因此,当您调用getClass().getGenericSuperclass().getRawType().getGenericSuperclass() (为了可读性省略了某些types转换),您将获得BaseDao<E> (注意<E>而不是<T> )。 由于getRawType()从types中getRawType()所有的typesvariables映射,我们从未映射的typesvariablesXE 。 然后getGenericSuperclass()只是将这些types的variables映射到它们在BaseDao的位置。

可以使用此行为,以便在遍历types层次结构时始终将typesvariables映射到其实际值。 当我们碰到我们想要的课程时,我们只需在地图上查找它的types参数即可。 这里是代码:

 @SuppressWarnings("unchecked") public static <T> Class<T> getGenericClassParameter(final Class<?> parameterizedSubClass, final Class<?> genericSuperClass, final int pos) { // a mapping from type variables to actual values (classes) Map<TypeVariable<?>, Class<?>> mapping = new HashMap<>(); Class<?> klass = parameterizedSubClass; while (klass != null) { Type type = klass.getGenericSuperclass(); if (type instanceof ParameterizedType) { ParameterizedType parType = (ParameterizedType) type; Type rawType = parType.getRawType(); if (rawType == genericSuperClass) { // found Type t = parType.getActualTypeArguments()[pos]; if (t instanceof Class<?>) { return (Class<T>) t; } else { return (Class<T>) mapping.get((TypeVariable<?>)t); } } // resolve Type[] vars = ((GenericDeclaration)(parType.getRawType())).getTypeParameters(); Type[] args = parType.getActualTypeArguments(); for (int i = 0; i < vars.length; i++) { if (args[i] instanceof Class<?>) { mapping.put((TypeVariable)vars[i], (Class<?>)args[i]); } else { mapping.put((TypeVariable)vars[i], mapping.get((TypeVariable<?>)(args[i]))); } } klass = (Class<?>) rawType; } else { klass = klass.getSuperclass(); } } throw new IllegalArgumentException("no generic supertype for " + parameterizedSubClass + " of type " + genericSuperClass); } 

如果Spring框架可用,你可以这样做:

 import org.springframework.core.GenericTypeResolver; public abstract class BaseDao<T extends PersistentObject> { protected Class<T> getClazz() { return (Class<T>) GenericTypeResolver.resolveTypeArgument(getClass(), BaseDao.class); } } 

如果你的课是抽象的,你可以试试这个:

 public class<T> getClassOfT() { final ParameterizedType type = (ParameterizedType) this.getClass() .getGenericSuperclass(); Class<T> clazz = (Class<T>) type.getActualTypeArguments()[0]; return clazz; } 

这只有在实例是直接子类时才有效 ,并且所需的types是第一个types(请参阅[0])。

如果你有一个很大的dao层次结构,你可以尝试recursion地searchBaseDao并获得参数化types

在这里看到一个例子(见底部的输出)

欢呼和抱歉,我的英语不好

以安全的方式对此问题进行sorting的常用方法是添加一个构造函数来存储types的类。 示例在您的上下文中:

 public abstract class BaseDao<T extends PersistentObject> { private Class<T> classT; BaseDao(Class<T> classT){ this.classT=classT; } protected Class<T> getClazz() { return classT; } // ... } 

你可以检查出TypeTools为这个:

 Class<T> t = (Class<T>)TypeResolver.resolveRawArgument(BaseDao.class, getClass());