我有一个像这样的课程:
public abstract class BaseDao<T extends PersistentObject> {
protected Class<T> getClazz() {
return T.class;
}
// ...
}
但是编译器说T.class;
:Illegal class literal for the type parameter T
。
我怎样才能得到类T
?
绝对可以从中提取它,Class#getGenericSuperclass()
因为它不是在运行时定义的,而是在编译时由FooDao extends BaseDao<Foo>
.
这是一个启动示例,您可以如何在抽象类的构造函数中提取所需的泛型超类型,同时考虑子类的层次结构(以及将其应用于泛型EntityManager
方法而无需显式提供类型的真实用例):
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 %s e ORDER BY id", type.getSimpleName()), type).getResultList();
}
// ...
}
实际上,这并不像看起来那么容易。当您拥有丰富的类型层次结构并希望在超类型中获取泛型参数时,就会出现问题。例如,您可能具有以下层次结构:
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> {
...
}
调用 returngetClass().getGenericSuperclass()
的实例,但是当你在方法内部调用它时MyDao
,你不知道泛型层次结构有多深。此外,据我所知,您无法获得超类型的通用超类型。因此,当您调用时(为了便于阅读,省略了一些类型转换),您将得到(notice而不是)。由于从类型中剥离了所有类型变量映射,我们从未映射的类型变量和. 然后只需将这些类型变量映射到它们在.SpecialDao<TypeImpl, EntityImpl>
BaseDao
getClass().getGenericSuperclass().getRawType().getGenericSuperclass()
BaseDao<E>
<E>
<T>
getRawType()
X
E
getGenericSuperclass()
BaseDao
可以使用此行为,以便我们在遍历类型层次结构时保持从类型变量到它们的实际值的映射。当我们点击我们想要的类时,我们只需在映射中查找它的类型参数。这是代码:
@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;
}
这仅在实例是直接子类时才有效,并且您想要的类的类型是第一个(参见 [0])。
如果你有很大的 dao 层次结构,你可以尝试递归地查找 BaseDao 并获取参数化类型
在此处查看示例(请参阅底部的输出)
为我糟糕的英语干杯和抱歉
以安全方式对这个问题进行排序的常用方法是添加一个构造函数来存储该类型的类。您的上下文中的示例:
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());