我有一个泛型类,Foo<T>。在Foo的一个方法中,我想获取T类型的类实例,但我无法调用T.class。
使用T.class绕过它的首选方法是什么?
我有一个泛型类,Foo<T>。在Foo的一个方法中,我想获取T类型的类实例,但我无法调用T.class。
使用T.class绕过它的首选方法是什么?
当前回答
这个问题由来已久,但现在最好的办法是使用谷歌Gson。
获取自定义视图模型的示例。
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>
}
}
其他回答
这个问题由来已久,但现在最好的办法是使用谷歌Gson。
获取自定义视图模型的示例。
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>
}
}
实际上,我想你的类中有一个T型字段。如果没有T型字段,那么有一个泛型类型有什么意义?因此,您可以简单地在该字段上执行实例化。
在我的情况下,我有一个列表<T>项;在我的类中,我检查类类型是否为“Locality”
if (items.get(0) instanceof Locality) ...
当然,这只在可能的类总数有限的情况下有效。
实际上,这是可能的(没有外部库!)
以下是我对这个问题的(丑陋但有效的)解决方案:
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 __() { }
}
然而,有一个小漏洞:如果您将Foo类定义为抽象类。这意味着您必须将类实例化为:
Foo<MyType> myFoo = new Foo<MyType>(){};
(注意末端的双撑杆。)
现在,您可以在运行时检索T的类型:
Type mySuperclass = myFoo.getClass().getGenericSuperclass();
Type tType = ((ParameterizedType)mySuperclass).getActualTypeArguments()[0];
然而,请注意,mySuperclass必须是实际定义T的最终类型的类定义的超类。
它也不是很优雅,但你必须决定你喜欢新的Foo<MyType>(){}还是新的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 );
}
}
这是一个有效的解决方案:
@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扩展Generic<Integer>)
OR
必须创建为匿名实现(new Generic<Integer>(){};)