协慌网

登录 贡献 社区

如何获得通用类型 T 的类实例?

我有一个泛型类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
    }
}

我一直在寻找一种无需添加额外的类路径依赖即可自行完成此操作的方法。经过一番调查,我发现,这可能的,只要你有一个通用的超类型。对于我来说,这很正常,因为我正在使用具有通用层超类型的 DAO 层。如果这符合您的情况,那是最整洁的方法恕我直言。

我遇到的大多数泛型用例都有某种泛型超类型,例如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 ";
    }

但是存在一个小漏洞:如果将Foo类定义为抽象。这意味着您必须将类实例化为:

Foo<MyType> myFoo = new Foo<MyType>(){};

(请注意末尾有两个大括号。)

现在,您可以在运行时T

Type mySuperclass = myFoo.getClass().getGenericSuperclass();
Type tType = ((ParameterizedType)mySuperclass).getActualTypeArguments()[0];

但是请注意, mySuperclass T的最终类型的类定义的超类。

它也不是很优雅,但是您必须决定是否要使用new Foo<MyType>(){}还是new Foo<MyType>(MyType.class);在您的代码中。


例如:

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.NoSuchElementException;

/**
 * Captures and silently ignores stack exceptions upon popping.
 */
public abstract class SilentStack<E> extends ArrayDeque<E> {
  public E pop() {
    try {
      return super.pop();
    }
    catch( NoSuchElementException nsee ) {
      return create();
    }
  }

  public E create() {
    try {
      Type sooper = getClass().getGenericSuperclass();
      Type t = ((ParameterizedType)sooper).getActualTypeArguments()[ 0 ];

      return (E)(Class.forName( t.toString() ).newInstance());
    }
    catch( Exception e ) {
      return null;
    }
  }
}

然后:

public class Main {
    // Note the braces...
    private Deque<String> stack = new SilentStack<String>(){};

    public static void main( String args[] ) {
      // Returns a new instance of String.
      String s = stack.pop();
      System.out.printf( "s = '%s'\n", s );
    }
}