如何获得具有 java 反射的列表的通用 class?
How to get the generic class of a list with java reflectioin?
我有一个局部变量 List 或其他一些 List
我想得到这个列表变量的泛型 class。
该变量不是成员变量,所以不要使用 Field 来获取泛型 class。
方法应该是
public Class<?> getGenericClass(List<E> list){
//somehow to return Class E
}
编辑: 我尝试了@Radiodef 的解决方案,但出现异常
java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class
在第 Class genericClazz = (Class) pt .getActualTypeArguments()[0]
.
行
public static void main(final String[] args) throws IOException {
final List<String> list = new ArrayList<String>();
list.add("aaa");
final Type type = list.getClass().getGenericSuperclass();
if (type instanceof ParameterizedType) {
final ParameterizedType pt = (ParameterizedType) type;
final Class<?> genericClazz = (Class<?>) pt
.getActualTypeArguments()[0];
System.out.println(genericClazz.getName());
}
}
编译器将 List 视为 List(没有类型信息),因此无法通过反射获取通用类型。
你能做什么:
- 扫描列表的每个元素并找到最具体的公共超级class
- 扫描列表的每个元素并找到所有公共接口
这两种方法都会遍历列表元素,然后反射性地扫描 class 层次结构。
这是唯一可以做到的方法:
import java.lang.reflect.*;
static <E> Class<E> getClassE(List<E> list) {
Class<?> listClass = list.getClass();
Type gSuper = listClass.getGenericSuperclass();
if(!(gSuper instanceof ParameterizedType))
throw new IllegalArgumentException();
ParameterizedType pType = (ParameterizedType)gSuper;
Type tArg = pType.getActualTypeArguments()[0];
if(!(tArg instanceof Class<?>))
throw new IllegalArgumentException();
@SuppressWarnings("unchecked")
final Class<E> classE = (Class<E>)tArg;
return classE;
}
但是,您传入的 List
必须 是具有具体类型的子类。
例如如果你打电话
... = getClassE( new ArrayList<String>() );
它会抛出:因为泛型是 erased,所以 Class<E>
通常在 运行 时不可用。
通常在使用这种模式时,你会使用一个匿名子类,例如:
// vv
... = getClassE( new ArrayList<String>() {} );
不过你也可以
class StringList extends ArrayList<String> {}
... = getClassE( new StringList() );
当我们像这样创建一个子类时,Class<E>
会被存储,我们可以通过我答案第一部分中的反射来检索它。
另见:http://gafter.blogspot.com/2006/12/super-type-tokens.html.
Ideone 的实际例子:http://ideone.com/O2Gztj.
我有一个局部变量 List 或其他一些 List 我想得到这个列表变量的泛型 class。
该变量不是成员变量,所以不要使用 Field 来获取泛型 class。
方法应该是
public Class<?> getGenericClass(List<E> list){
//somehow to return Class E
}
编辑: 我尝试了@Radiodef 的解决方案,但出现异常
java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class
在第 Class genericClazz = (Class) pt .getActualTypeArguments()[0]
.
public static void main(final String[] args) throws IOException {
final List<String> list = new ArrayList<String>();
list.add("aaa");
final Type type = list.getClass().getGenericSuperclass();
if (type instanceof ParameterizedType) {
final ParameterizedType pt = (ParameterizedType) type;
final Class<?> genericClazz = (Class<?>) pt
.getActualTypeArguments()[0];
System.out.println(genericClazz.getName());
}
}
编译器将 List 视为 List(没有类型信息),因此无法通过反射获取通用类型。
你能做什么:
- 扫描列表的每个元素并找到最具体的公共超级class
- 扫描列表的每个元素并找到所有公共接口
这两种方法都会遍历列表元素,然后反射性地扫描 class 层次结构。
这是唯一可以做到的方法:
import java.lang.reflect.*;
static <E> Class<E> getClassE(List<E> list) {
Class<?> listClass = list.getClass();
Type gSuper = listClass.getGenericSuperclass();
if(!(gSuper instanceof ParameterizedType))
throw new IllegalArgumentException();
ParameterizedType pType = (ParameterizedType)gSuper;
Type tArg = pType.getActualTypeArguments()[0];
if(!(tArg instanceof Class<?>))
throw new IllegalArgumentException();
@SuppressWarnings("unchecked")
final Class<E> classE = (Class<E>)tArg;
return classE;
}
但是,您传入的 List
必须 是具有具体类型的子类。
例如如果你打电话
... = getClassE( new ArrayList<String>() );
它会抛出:因为泛型是 erased,所以 Class<E>
通常在 运行 时不可用。
通常在使用这种模式时,你会使用一个匿名子类,例如:
// vv
... = getClassE( new ArrayList<String>() {} );
不过你也可以
class StringList extends ArrayList<String> {}
... = getClassE( new StringList() );
当我们像这样创建一个子类时,Class<E>
会被存储,我们可以通过我答案第一部分中的反射来检索它。
另见:http://gafter.blogspot.com/2006/12/super-type-tokens.html.
Ideone 的实际例子:http://ideone.com/O2Gztj.