如何获得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();