如何获得泛型类型t的类示例?

lokaqttq  于 2021-07-14  发布在  Java
关注(0)|答案(22)|浏览(747)

我有个泛型课, Foo<T> . 以一种 Foo ,我要获取类型的类示例 T ,但我就是打不来 T.class .
用什么方法绕过它 T.class ?

ej83mcc0

ej83mcc016#

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

mrfwxfqh

mrfwxfqh17#

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

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

后来在派生类上:

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

6psbrbz918#

以下是一个可行的解决方案:

@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 extends Generic<Integer> )

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

nsc4cvqm

nsc4cvqm19#

假设您有一个抽象的泛型超类:

public abstract class Foo<? extends T> {}

还有第二个类用一个泛型条扩展foo,泛型条扩展t:

public class Second extends Foo<Bar> {}

你可以去上课 Bar.class 在foo类中选择 Type (来自伯特·布鲁尼的回答)并用 Class 示例:

Type mySuperclass = myFoo.getClass().getGenericSuperclass();
Type tType = ((ParameterizedType)mySuperclass).getActualTypeArguments()[0];
//Parse it as String
String className = tType.toString().split(" ")[1];
Class clazz = Class.forName(className);

必须注意,此操作并不理想,因此最好缓存计算值,以避免对此进行多次计算。一个典型的用法是在泛型dao实现中。
最终实施:

public abstract class Foo<T> {

    private Class<T> inferedClass;

    public Class<T> getGenericClass(){
        if(inferedClass == null){
            Type mySuperclass = getClass().getGenericSuperclass();
            Type tType = ((ParameterizedType)mySuperclass).getActualTypeArguments()[0];
            String className = tType.toString().split(" ")[1];
            inferedClass = Class.forName(className);
        }
        return inferedClass;
    }
}

当从其他函数中的foo类或bar类调用时,返回的值是bar.class。

mnowg1ta

mnowg1ta20#

标准方法/解决方法/解决方案是添加 class 对象,例如:

public class Foo<T> {

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

    public Class<T> getType() {
      return type;
    }

    public T newInstance() {
      return type.newInstance();
    }
 }
lzfw57am

lzfw57am21#

但是有一个小漏洞:如果你定义你的 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 );
    }
}
zkure5ic

zkure5ic22#

我一直在寻找一种方法来实现这一点,而不需要向类路径添加额外的依赖项。经过一些调查,我发现这是可能的,只要你有一个泛型超类型。这对我来说还可以,因为我正在使用一个带有泛型层超类型的dao层。如果这符合你的情况,那么这是最整洁的方法。
我遇到的大多数泛型用例都有某种泛型超类型。 List<T> 为了 ArrayList<T> 或者 GenericDAO<T> 为了 DAO<T> 等等。

纯java解决方案

在java中访问运行时泛型类型的文章解释了如何使用纯java来实现。

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

Spring解决方案

我的项目是使用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 ";
    }

相关问题