我有一个泛型类,Foo<T>。在Foo的一个方法中,我想获取T类型的类实例,但我无法调用T.class。

使用T.class绕过它的首选方法是什么?


当前回答

简单的答案是,无法找出Java中泛型类型参数的运行时类型。我建议阅读Java教程中有关类型擦除的章节以了解更多详细信息。

对此,一个流行的解决方案是将类型参数的Class传递给泛型类型的构造函数,例如。

class Foo<T> {
    final Class<T> typeParameterClass;

    public Foo(Class<T> typeParameterClass) {
        this.typeParameterClass = typeParameterClass;
    }

    public void bar() {
        // you can access the typeParameterClass here and do whatever you like
    }
}

其他回答

很多人不知道这个把戏!事实上,我今天刚找到它!它就像一个梦!请查看以下示例:

public static void main(String[] args) {
    Date d=new Date();  //Or anything you want!
    printMethods(d);
}

public static <T> void printMethods(T t){
    Class<T> clazz= (Class<T>) t.getClass(); // There you go!
    for ( Method m : clazz.getMethods()){
        System.out.println( m.getName() );
    }
}

我找到了一种通用而简单的方法。在我的类中,我创建了一个方法,该方法根据泛型类型在类定义中的位置返回泛型类型。让我们假设一个类定义如下:

public class MyClass<A, B, C> {

}

现在,让我们创建一些属性来持久化类型:

public class MyClass<A, B, C> {

    private Class<A> aType;

    private Class<B> bType;

    private Class<C> cType;

// Getters and setters (not necessary if you are going to use them internally)

    } 

然后,您可以创建一个基于泛型定义的索引返回类型的泛型方法:

   /**
     * Returns a {@link Type} object to identify generic types
     * @return type
     */
    private Type getGenericClassType(int index) {
        // To make it use generics without supplying the class type
        Type type = getClass().getGenericSuperclass();

        while (!(type instanceof ParameterizedType)) {
            if (type instanceof ParameterizedType) {
                type = ((Class<?>) ((ParameterizedType) type).getRawType()).getGenericSuperclass();
            } else {
                type = ((Class<?>) type).getGenericSuperclass();
            }
        }

        return ((ParameterizedType) type).getActualTypeArguments()[index];
    }

最后,在构造函数中,只需调用方法并发送每个类型的索引。完整的代码应该如下所示:

public class MyClass<A, B, C> {

    private Class<A> aType;

    private Class<B> bType;

    private Class<C> cType;


    public MyClass() {
      this.aType = (Class<A>) getGenericClassType(0);
      this.bType = (Class<B>) getGenericClassType(1);
      this.cType = (Class<C>) getGenericClassType(2);
    }

   /**
     * Returns a {@link Type} object to identify generic types
     * @return type
     */
    private Type getGenericClassType(int index) {

        Type type = getClass().getGenericSuperclass();

        while (!(type instanceof ParameterizedType)) {
            if (type instanceof ParameterizedType) {
                type = ((Class<?>) ((ParameterizedType) type).getRawType()).getGenericSuperclass();
            } else {
                type = ((Class<?>) type).getGenericSuperclass();
            }
        }

        return ((ParameterizedType) type).getActualTypeArguments()[index];
    }
}

这是一个有效的解决方案:

@SuppressWarnings("unchecked")
private Class<T> getGenericTypeClass() {
    try {
        String className = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0].getTypeName();
        Class<?> clazz = Class.forName(className);
        return (Class<T>) clazz;
    } catch (Exception e) {
        throw new IllegalStateException("Class is not parametrized with generic type!!! Please use extends <> ");
    }
} 

笔记:只能用作超类

必须使用类型化类进行扩展(Child扩展Generic<Integer>)

OR

必须创建为匿名实现(new Generic<Integer>(){};)

我假设,既然你有一个泛型类,你会有一个这样的变量:

private T t;

(此变量需要在构造函数中取值)

在这种情况下,您可以简单地创建以下方法:

Class<T> getClassOfInstance()
{
    return (Class<T>) t.getClass();
}

希望它有帮助!

我一直在寻找一种不向类路径添加额外依赖项的方法。经过一些调查,我发现只要你有一个泛型超类型,这是可能的。这对我来说是可以的,因为我正在使用一个具有通用层超类型的DAO层。如果这符合您的情况,那么这是IMHO最整洁的方法。

我遇到的大多数泛型用例都有某种泛型超类型,例如ArrayList<T>的List<T>或DAO<T>的GenericDAO<T>等。

纯Java解决方案

在Java运行时访问泛型类型一文解释了如何使用纯Java实现这一点。

@SuppressWarnings("unchecked")
public GenericJpaDao() {
  this.entityBeanType = ((Class) ((ParameterizedType) getClass()
      .getGenericSuperclass()).getActualTypeArguments()[0]);
}

弹簧解决方案

我的项目使用的是Spring,它甚至更好,因为Spring有一个方便的实用方法来查找类型。这是对我来说最好的方法,因为它看起来最整洁。我想如果你不使用Spring,你可以编写自己的实用程序方法。

import org.springframework.core.GenericTypeResolver;

public abstract class AbstractHibernateDao<T extends DomainObject> implements DataAccessObject<T>
{

    @Autowired
    private SessionFactory sessionFactory;

    private final Class<T> genericType;

    private final String RECORD_COUNT_HQL;
    private final String FIND_ALL_HQL;

    @SuppressWarnings("unchecked")
    public AbstractHibernateDao()
    {
        this.genericType = (Class<T>) GenericTypeResolver.resolveTypeArgument(getClass(), AbstractHibernateDao.class);
        this.RECORD_COUNT_HQL = "select count(*) from " + this.genericType.getName();
        this.FIND_ALL_HQL = "from " + this.genericType.getName() + " t ";
    }

完整代码示例

有些人在评论中很难让这种方法发挥作用,所以我写了一个小应用程序来展示这两种方法。https://github.com/benthurley82/generic-type-resolver-test