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

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


当前回答

你不能这样做,因为类型删除。另请参阅堆栈溢出问题Java泛型-类型擦除-何时发生以及发生什么。

其他回答

这很直接。如果您需要来自同一类:

Class clazz = this.getClass();
ParameterizedType parameterizedType = (ParameterizedType) clazz.getGenericSuperclass();
try {
        Class typeClass = Class.forName( parameterizedType.getActualTypeArguments()[0].getTypeName() );
        // You have the instance of type 'T' in typeClass variable

        System.out.println( "Class instance name: "+  typeClass.getName() );
    } catch (ClassNotFoundException e) {
        System.out.println( "ClassNotFound!! Something wrong! "+ e.getMessage() );
    }

我正在使用解决方法:

class MyClass extends Foo<T> {
....
}

MyClass myClassInstance = MyClass.class.newInstance();

简单的答案是,无法找出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
    }
}

我一直在寻找一种不向类路径添加额外依赖项的方法。经过一些调查,我发现只要你有一个泛型超类型,这是可能的。这对我来说是可以的,因为我正在使用一个具有通用层超类型的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

我在抽象泛型类中遇到了这个问题。在这种特殊情况下,解决方案更简单:

abstract class Foo<T> {
    abstract Class<T> getTClass();
    //...
}

以及随后的派生类:

class Bar extends Foo<Whatever> {
    @Override
    Class<T> getTClass() {
        return Whatever.class;
    }
}