如何确定一个generics的类?
我正在创build一个generics类,在我需要知道当前正在使用的generics类的一个方法。 原因在于我所称的方法之一就是期待这个论点。
例:
public class MyGenericClass<T> { public void doSomething() { // Snip... // Call to a 3rd party lib T bean = (T)someObject.create(T.class); // Snip... } }
显然,上面的例子不起作用,导致以下错误:types参数T的非法类文字。
我的问题是:有人知道一个很好的替代或解决方法?
仍然是同样的问题:通用信息在运行时被擦除,它不能被恢复。 一个解决方法是在一个静态方法的参数中传递类T:
public class MyGenericClass<T> { private final Class<T> clazz; public static <U> MyGenericClass<U> createMyGeneric(Class<U> clazz) { return new MyGenericClass<U>(clazz); } protected MyGenericClass(Class<T> clazz) { this.clazz = clazz; } public void doSomething() { T instance = clazz.newInstance(); } }
这是丑陋的,但它的作品。
我只是指出了这个解决scheme:
import java.lang.reflect.ParameterizedType; public abstract class A<B> { public Class<B> g() throws Exception { ParameterizedType superclass = (ParameterizedType) getClass().getGenericSuperclass(); return (Class<B>) superclass.getActualTypeArguments()[0]; } }
如果A
通过子类给出具体types,这是有效的:
new A<String>() {}.g() // this will work class B extends A<String> {} new B().g() // this will work class C<T> extends A<T> {} new C<String>().g() // this will NOT work
不幸的是,Christoph的解决scheme只能在非常有限的情况下使用。 [编辑:作为下面的评论我不再记得我的推理这个句子,它可能是错误的:“注意,这将只能在抽象类,首先。”]下一个困难是, g()
只能从直接A
子类。 不过,我们可以解决这个问题:
private Class<?> extractClassFromType(Type t) throws ClassCastException { if (t instanceof Class<?>) { return (Class<?>)t; } return (Class<?>)((ParameterizedType)t).getRawType(); } public Class<B> g() throws ClassCastException { Class<?> superClass = getClass(); // initial value Type superType; do { superType = superClass.getGenericSuperclass(); superClass = extractClassFromType(superType); } while (! (superClass.equals(A.class))); Type actualArg = ((ParameterizedType)superType).getActualTypeArguments()[0]; return (Class<B>)extractClassFromType(actualArg); }
这将在实践中的许多情况下工作,但不是所有的时间。 考虑:
public class Foo<U,T extends Collection<?>> extends A<T> {} (new Foo<String,List<Object>>() {}).g();
这将抛出一个ClassCastException
,因为这里的types参数根本不是一个Class
或一个ParameterizedType
; 这是TypeVariable
T
所以现在你会被卡住试图弄清楚T
应该代表什么types,等等。
我认为唯一合理的,一般的答案类似于Nicolas的初始答案 – 一般来说,如果你的类需要在编译时实例化其他一些未知类的对象,那么你的类的用户需要传递这个类的文字(或者也许是一个工厂),而不是仅仅依靠generics。
我find另一种方法来获得通用对象的类
public Class<?> getGenericClass(){ Class<?> result =null; Type type =this.getClass().getGenericSuperclass(); if(type instanceofParameterizedType){ ParameterizedType pt =(ParameterizedType) type; Type[] fieldArgTypes = pt.getActualTypeArguments(); result =(Class<?>) fieldArgTypes[0]; } return result; }
我将详细阐述克里斯托夫的解决scheme。
这里是ClassGetter抽象类:
private abstract class ClassGetter<T> { public final Class<T> get() { final ParameterizedType superclass = (ParameterizedType) getClass().getGenericSuperclass(); return (Class<T>)superclass.getActualTypeArguments()[0]; } }
这是一个静态的方法,它使用上面的类来find一个generics类的types:
public static <T> Class<T> getGenericClass() { return new ClassGetter<T>() {}.get(); }
作为它的用法的一个例子,你可以做这个方法:
public static final <T> T instantiate() { final Class<T> clazz = getGenericClass(); try { return clazz.getConstructor((Class[])null).newInstance(null); } catch (Exception e) { return null; } }
然后像这样使用它:
T var = instantiate();
T可以使用TypeTools很容易地解决:
Class<T> t = (Class<T>) TypeResolver.resolveRawArguments( MyGenericClass.class, getClass());