在抽象超类上获取泛型类型参数的实际类型

t77*_*777 12 java generics dao jpa

我有一个类:

public abstract class BaseDao<T extends PersistentObject> {

  protected Class<T> getClazz() {
     return T.class;
  }

  // ...

}
Run Code Online (Sandbox Code Playgroud)

但是编译器说T.class;:Illegal class literal for the type parameter T.

我怎样才能上课T

Bal*_*usC 22

它绝对有可能从中提取它,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();
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)


Mar*_*bek 12

实际上,这并不像看起来那么容易.如果您具有丰富的类型层次结构并且想要在超类型中获取泛型参数,则会出现问题.例如,您可能具有以下层次结构:

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> {
...
}
Run Code Online (Sandbox Code Playgroud)

调用返回getClass().getGenericSuperclass()的实例,但是当您在方法内部调用它时,您不知道通用层次结构有多深.而且,据我所知,你无法获得超类型的通用超类型.因此,当您调用(为了便于阅读省略某些类型转换)时,您将获得(通知而不是).由于从类型片的所有类型变量映射,我们开始用映射的类型变量和.然后将这些类型变量映射到它们的位置.MyDaoSpecialDao<TypeImpl, EntityImpl>BaseDaogetClass().getGenericSuperclass().getRawType().getGenericSuperclass()BaseDao<E><E><T>getRawType()XEgetGenericSuperclass()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);
}
Run Code Online (Sandbox Code Playgroud)


Art*_*lpe 7

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

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

这仅在实例是直接子类时才有效,并且您想要的类的类型是第一个(参见[0]).

如果你有一个很大的dao层次结构,你可以尝试递归地输入BaseDao并获得参数化类型

在这里查看示例(参见底部的输出)

干杯,抱歉我的英语不好


eug*_*e82 6

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

}
Run Code Online (Sandbox Code Playgroud)