如何获得genericstypesT的类实例

我有一个generics类Foo<T> 。 在Foo一个方法中,我想获得typesT的类实例,但是我不能调用T.class

什么是使用T.class解决它的首选方法?

简单的答案是,没有办法findJava中genericstypes参数的运行时types。 我build议阅读Java教程中关于types擦除的章节以获取更多细节。

一个stream行的解决scheme是将types参数的Class传递给generics的构造函数,例如

 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 } } 

我正在寻找一种方法来做到这一点,而无需增加额外的依赖到类path。 经过一番调查,我发现只要你有一个通用的超types,就有可能。 这对我来说是好的,因为我正在处理带有generics层超types的DAO层。 如果这符合你的情况,那么这是最好的方法恕我直言。

我遇到的大多数generics用例都具有某种通用超types,例如ArrayList<T> List<T> ArrayList<T>DAO<T> GenericDAO<T>等。

纯Java解决scheme

在Java中运行时访问genericstypes的文章解释了如何使用纯Java来完成。

Spring解决scheme

我的项目使用了Spring ,因为Spring有一个方便的实用方法来查找types。 这对我来说是最好的方法,因为它看起来很新奇。 我猜如果你不使用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的types:

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

但是请注意, mySuperclass必须是实际定义T的最终types的类定义的超类。

它也不是很优雅,但是你必须决定你是否喜欢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 ); } } 

一个标准的方法/解决方法是将一个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(); } } 

想象一下你有一个通用的抽象超类:

 public abstract class Foo<? extends T> {} 

然后你有第二个类扩展Foo与扩展T的通用酒吧:

 public class Second extends Foo<Bar> {} 

你可以通过selectType (来自bert bruynooghe答案)并使用Class实例来推断它在Foo类中获得Bar.class 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); 

你必须注意到这个操作并不理想,因此caching计算值以避免多重计算是一个好主意。 其中一个典型的用途是在通用的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。

这里是工作解决scheme!

 @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 <> ");    } } 

注意: 只能用作超类
1.必须用types化类扩展( Child extends Generic<Integer>
要么
2.必须创build为匿名实现( new Generic<Integer>() {};

你不能这样做,因为types的删除。 另请参见堆栈溢出问题Javagenerics – types擦除 – 何时发生

比别人build议的更好的路线是传入一个对象,可以完成你对类的处理,例如创build一个新的实例。

 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>()); 

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

 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); } 

你需要svn / trunk / dao / src / main / java / com / googlecode / genericdao / dao / DAOUtil.java这两个函数 。

有关更多解释,请参阅反映generics

  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 } } 

如果您正在扩展或实现任何正在使用generics的类/接口,则可能会获得generics类的父类/接口,而不会修改任何现有的类/接口。

可能有三种可能性,

案例1当你的class级正在扩展一个正在使用generics的类

 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> { } 

案例2当你的class正在实施一个使用generics的界面

 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){} } 

情况3当您的界面正在扩展使用generics的界面

 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> { } 

实际上,我想你在你的typesT中有一个字段。如果没有Ttypes的字段,那么有一个genericstypes有什么意义呢? 所以,你可以简单地在这个领域做一个instanceof。

就我而言,我有一个

 列出<T>项目; 

在我的课,我检查类types是“地点”通过

 如果(items.get(0)instanceof Locality)...

当然,这只有在可能的课程总数有限的情况下才有效。

正如其他答案中所解释的那样,要使用这种ParameterizedType方法,你需要扩展这个类,但是这看起来像是额外的工作,使一个新的类扩展它…

所以,使得抽象类迫使你扩展它,从而满足子类的要求。 (使用lombok的@Getter)。

 @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> ins = new __<T>(); TypeVariable<?>[] cls = ins.getClass().getTypeParameters(); return (Class<T>)cls[0].getClass(); } private final class __<T> // generic helper class which does only provide type information { private __() { } } 

我正在使用这个解决方法:

 class MyClass extends Foo<T> { .... } MyClass myClassInstance = MyClass.class.newInstance();