Java 如何获取泛型类型T的类实例?

Java 如何获取泛型类型T的类实例?,java,generics,Java,Generics,我有一个泛型类,Foo。在Foo的方法中,我想获取类型为T的类实例,但我无法调用T.class 使用T.class绕过它的首选方法是什么?由于类型擦除,您不能这样做。另请参见堆栈溢出问题。简短的回答是,在Java中无法找到泛型类型参数的运行时类型。我建议阅读中有关类型擦除的章节以了解更多详细信息 对此,一种流行的解决方案是将类型参数的类传递到泛型类型的构造函数中,例如 class Foo<T> { final Class<T> typeParameterClass

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


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

由于类型擦除,您不能这样做。另请参见堆栈溢出问题。

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

对此,一种流行的解决方案是将类型参数的
传递到泛型类型的构造函数中,例如

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
    }
}
class-Foo{
最终类typeParameterClass;
公共Foo(类类型参数类){
this.typeParameterClass=typeParameterClass;
}
公共空白栏(){
//您可以在这里访问typeParameterClass并执行任何您喜欢的操作
}
}

标准方法/解决方法/解决方案是向构造函数添加
对象,如:

公共类Foo{
私人阶级类型;
公共Foo(类类型){
this.type=type;
}
公共类getType(){
返回类型;
}
公共T newInstance(){
返回类型:newInstance();
}
}

与其他人建议的类相比,更好的方法是传入一个对象,该对象可以执行与该类相同的操作,例如,创建一个新实例

interface Factory<T> {
  T apply();
}

<T> void List<T> make10(Factory<T> factory) {
  List<T> result = new ArrayList<T>();
  for (int a = 0; a < 10; a++)
    result.add(factory.apply());
  return result;
}

class FooFactory<T> implements Factory<Foo<T>> {
  public Foo<T> apply() {
    return new Foo<T>();
  }
}

List<Foo<Integer>> foos = make10(new FooFactory<Integer>());
接口工厂{
T apply();
}
作废清单make10(工厂){
列表结果=新建ArrayList();
对于(int a=0;a<10;a++)
result.add(factory.apply());
返回结果;
}
类FooFactory实现工厂{
公共Foo apply(){
返回新的Foo();
}
}
listfoos=make10(newfoodfactory());

然而,有一个小漏洞:如果将
Foo
类定义为抽象类。 这意味着您必须将类实例化为:

Foo<MyType> myFoo = new Foo<MyType>(){};
但是请注意,
mySuperclass
必须是类定义的超类,实际上定义了
T
的最终类型

它也不是很优雅,但是您必须决定是喜欢
newfoo(){}
还是
newfoo(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;
    }
  }
}
import java.lang.reflect.ParameterizedType;
导入java.lang.reflect.Type;
导入java.util.ArrayDeque;
导入java.util.Deque;
导入java.util.NoSuchElementException;
/**
*捕获并在弹出时以静默方式忽略堆栈异常。
*/
公共抽象类SilentStack扩展了ArrayDeque{
公共E-pop(){
试一试{
返回super.pop();
}
捕获(非接触元素异常nsee){
返回create();
}
}
公共E创建(){
试一试{
类型sooper=getClass().getGenericSuperclass();
类型t=((ParameteredType)sooper.getActualTypeArguments()[0];
return(E)(Class.forName(t.toString()).newInstance());
}
捕获(例外e){
返回null;
}
}
}
然后:

公共类主{
//注意大括号。。。
private Deque stack=new SilentStack(){};
公共静态void main(字符串参数[]){
//返回字符串的新实例。
字符串s=stack.pop();
System.out.printf(“s='%s'\n',s);
}
}

事实上,我假设您的类中有一个类型为T的字段。如果没有类型为T的字段,使用泛型类型有什么意义?所以,您可以简单地在该字段上执行instanceof

在我的例子中,我有一个列表项;在我的类中,我通过

List<T> items; 如果(items.get(0)instanceof Locality)。。。
当然,这只有在可能的类的总数有限的情况下才起作用。

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

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

纯Java解决方案 本文解释了如何使用纯Java实现这一点

@SuppressWarnings("unchecked")
public GenericJpaDao() {
  this.entityBeanType = ((Class) ((ParameterizedType) getClass()
      .getGenericSuperclass()).getActualTypeArguments()[0]);
}
弹簧溶液 我的项目使用了更好的方法,因为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 ";
    }
import org.springframework.core.GenericTypeResolver;
公共抽象类AbstractHibernateDao实现DataAccessObject
{
@自动连线
私人会话工厂会话工厂;
私有final类genericType;
私有最终字符串记录\u计数\u HQL;
私有最终字符串FIND_ALL_HQL;
@抑制警告(“未选中”)
公开摘要HibernateDao()
{
this.genericType=(类)GenericTypeResolver.resolveTypeArgument(getClass(),AbstractHibernateDao.Class);
this.RECORD_COUNT_HQL=“从”+this.genericType.getName()中选择COUNT(*);
this.FIND_ALL_HQL=“from”+this.genericType.getName()+“t”;
}

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

abstract class Foo<T> {
    abstract Class<T> getTClass();
    //...
}
抽象类Foo{
抽象类getClass();
//...
}
然后在派生类上:

class Bar extends Foo<Whatever> {
    @Override
    Class<T> getTClass() {
        return Whatever.class;
    }
}
类栏扩展了Foo{
@凌驾
类getTClass(){
返回任何.class;
}
}
有可能:

class Foo<T> {
  Class<T> clazz = (Class<T>) DAOUtil.getTypeArguments(Foo.class, this.getClass()).get(0);
}
class-Foo{
类clazz=(类)DAOUtil.getTypeArguments(Foo.Class,this.getClass()).get(0);
}
您需要来自的两个函数


有关更多解释,请参见。

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

public abstract class Foo<? extends T> {}
您必须注意,此操作并不理想,因此它是一个
abstract class Foo<T> {
    abstract Class<T> getTClass();
    //...
}
class Bar extends Foo<Whatever> {
    @Override
    Class<T> getTClass() {
        return Whatever.class;
    }
}
class Foo<T> {
  Class<T> clazz = (Class<T>) DAOUtil.getTypeArguments(Foo.class, this.getClass()).get(0);
}
public abstract class Foo<? extends T> {}
public class Second extends Foo<Bar> {}
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);
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;
    }
}
   public <T> T yourMethodSignature(Class<T> type) {

        // get some object and check the type match the given type
        Object result = ...            

        if (type.isAssignableFrom(result.getClass())) {
            return (T)result;
        } else {
            // handle the error
        }
   }
@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 <> ");
    }
} 
public class TestGenerics {
    public static void main(String[] args) {
        Type type = TestMySuperGenericType.class.getGenericSuperclass();
        Type[] gTypes = ((ParameterizedType)type).getActualTypeArguments();
        for(Type gType : gTypes){
            System.out.println("Generic type:"+gType.toString());
        }
    }
}

class GenericClass<T> {
    public void print(T obj){};
}

class TestMySuperGenericType extends GenericClass<Integer> {
}
public class TestGenerics {
    public static void main(String[] args) {
        Type[] interfaces = TestMySuperGenericType.class.getGenericInterfaces();
        for(Type type : interfaces){
            Type[] gTypes = ((ParameterizedType)type).getActualTypeArguments();
            for(Type gType : gTypes){
                System.out.println("Generic type:"+gType.toString());
            }
        }
    }
}

interface GenericClass<T> {
    public void print(T obj);
}

class TestMySuperGenericType implements GenericClass<Integer> {
    public void print(Integer obj){}
}
public class TestGenerics {
    public static void main(String[] args) {
        Type[] interfaces = TestMySuperGenericType.class.getGenericInterfaces();
        for(Type type : interfaces){
            Type[] gTypes = ((ParameterizedType)type).getActualTypeArguments();
            for(Type gType : gTypes){
                System.out.println("Generic type:"+gType.toString());
            }
        }
    }
}

interface GenericClass<T> {
    public void print(T obj);
}

interface TestMySuperGenericType extends GenericClass<Integer> {
}
class MyClass extends Foo<T> {
....
}

MyClass myClassInstance = MyClass.class.newInstance();
@Getter
public abstract class ConfigurationDefinition<T> {

    private Class<T> type;
    ...

    public ConfigurationDefinition(...) {
        this.type = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        ...
    }
}
private ConfigurationDefinition<String> myConfigA = new ConfigurationDefinition<String>(...){};
private ConfigurationDefinition<File> myConfigB = new ConfigurationDefinition<File>(...){};
...
Class stringType = myConfigA.getType();
Class fileType = myConfigB.getType();
import java.lang.reflect.TypeVariable;


public static <T> Class<T> getGenericClass() {
    __<T> instance = new __<T>();
    TypeVariable<?>[] parameters = instance.getClass().getTypeParameters(); 

    return (Class<T>)parameters[0].getClass();
}

// Generic helper class which (only) provides type information. This avoids the usage
// of a local variable of type T, which would have to be initialized.
private final class __<T> {
    private __() {
    }
}
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];
    }
}
Class<CustomViewModel<String>> clazz = new GenericClass<CustomViewModel<String>>().getRawType();
CustomViewModel<String> viewModel = viewModelProvider.get(clazz);
class GenericClass<T>(private val rawType: Class<*>) {

    constructor():this(`$Gson$Types`.getRawType(object : TypeToken<T>() {}.getType()))

    fun getRawType(): Class<T> {
        return rawType as Class<T>
    }
}
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() );
    }
private T t;
Class<T> getClassOfInstance()
{
    return (Class<T>) t.getClass();
}
private <T>List<T> readFile(String fileName, Class<? extends T> type) {

    List<T> dataList = new ArrayList<T>();
    try {
        File file = new File(fileName);

        Reader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
        Reader headerReader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));

        CSVReader csvReader = new CSVReader(headerReader);
        // create csv bean reader
        CsvToBean<T> csvToBean = new CsvToBeanBuilder(reader)
                .withType(type)
                .withIgnoreLeadingWhiteSpace(true)
                .build();

        dataList = csvToBean.parse();
    }
    catch (Exception ex) {
        logger.error("Error: ", ex);
    }

    return dataList;
}
List<RigSurfaceCSV> rigSurfaceCSVDataList = readSurfaceFile(surfaceFileName, RigSurfaceCSV.class);
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() );
    }
}