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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18707582/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 10:22:04  来源:igfitidea点击:

Get actual type of generic type argument on abstract superclass

javagenericsjpadao

提问by t777

I have a class like:

我有一个类:

public abstract class BaseDao<T extends PersistentObject> {

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

  // ...

}

But the compiler says to T.class;: Illegal class literal for the type parameter T.

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

How can I get the class of T?

我怎样才能得到 的类T

采纳答案by BalusC

It's definitely possible to extract it from Class#getGenericSuperclass()because it's not defined during runtime, but during compiletime by FooDao extends BaseDao<Foo>.

绝对可以从中提取它,Class#getGenericSuperclass()因为它不是在运行时定义的,而是在编译时由FooDao extends BaseDao<Foo>.

Here's a kickoff example how you could extract the desired generic super type in the constructor of the abstract class, taking a hierarchy of subclasses into account (along with a real world use case of applying it on generic EntityManagermethods without the need to explicitly supply the type):

这是一个启动示例,说明如何在抽象类的构造函数中提取所需的泛型超类型,同时考虑子类的层次结构(以及将其应用于泛型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();
    }

    // ...
}

回答by Farid

Common way to sort this issue in a secure way is to add a constructor to store the class of the type. Example in your context:

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

public abstract class BaseDao<T extends PersistentObject> {
  private Class<T> classT;

  BaseDao(Class<T> classT){
    this.classT=classT;
  }

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

  // ...

}

回答by Arturo Volpe

If your class is abstract, you can try with this:

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

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

This only work if the instance is a direct subclass, and the type of the class you want is the first one (see the [0]).

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

If you have a large hierarchy of dao's, you can try fidn the BaseDao recursively and get the parametrized type

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

See a example here(see the output in the bottom)

请参阅此处的示例(请参阅底部的输出)

Cheers and sorry for my bad english

为我的英语不好而干杯和抱歉

回答by Jonathan

You might check out TypeToolsfor this:

您可以为此查看TypeTools

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

回答by Marcel ?ebek

Actually, this is not as easy as it seems. There is a problem when you have rich type hierarchy and want to get generic parameter in the supertype. For example, you may have the following hierarchy:

实际上,这并不像看起来那么容易。当您拥有丰富的类型层次结构并希望在超类型中获取泛型参数时,就会出现问题。例如,您可能具有以下层次结构:

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> {
...
}

Calling getClass().getGenericSuperclass()in an instance of MyDaoreturns SpecialDao<TypeImpl, EntityImpl>, but when you call it inside BaseDaomethod, you don't know how deep the generic hierarchy is. Moreover, as far as I know, you cannot obtain generic supertype of a supertype. Thus, when you invoke getClass().getGenericSuperclass().getRawType().getGenericSuperclass()(with some typecasting omitted for readability), you'll get BaseDao<E>(notice <E>instead of <T>). Since getRawType()strips all type-variable mapping from the type, we're starting with unmapped type variables Xand E. Then getGenericSuperclass()just maps these type variables to their positions in BaseDao.

调用getClass().getGenericSuperclass()的实例MyDao回报SpecialDao<TypeImpl, EntityImpl>,但是当你把它里面BaseDao的方法,你不知道一般的层次有多深。此外,据我所知,您无法获得超类型的泛型超类型。因此,当您调用时getClass().getGenericSuperclass().getRawType().getGenericSuperclass()(为了可读性省略了一些类型转换),您将得到BaseDao<E>(注意<E>而不是<T>)。由于getRawType()从类型中剥离了所有类型变量映射,我们从未映射的类型变量XE. 然后getGenericSuperclass()只需将这些类型变量映射到它们在BaseDao.

This behavior can be used so that we keep mapping from type variables to their actual values while traversing the type hierarchy. When we hit the class we want, we simply look up its type parameters in the map. Here is the code:

可以使用此行为,以便我们在遍历类型层次结构时保持从类型变量到它们的实际值的映射。当我们点击我们想要的类时,我们只需在地图中查找它的类型参数。这是代码:

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

回答by eugene82

If Spring framework is available, you can do like here:

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

}