我想请求一个项目集合(特定反射的种类)。但关于类型擦除似乎是不可能的,也是关于我在堆栈上阅读的一些主题。有一些解决方法(here),但我很好奇,如果有人知道它是如何完成的,例如DWR:
http://directwebremoting.org/dwr/documentation/server/configuration/dwrxml/signatures.html
或者如果有更好的解决方法,那就太棒了。
我们说我们有类似的东西:
public String foo(List<String> possibleFoos) {
我需要的是找出参数possibleFoos是字符串列表,而不仅仅是List
答案 0 :(得分:6)
虽然Java会在运行时擦除类型(因此将List<String>
转换为List
),但在很多情况下它实际上会在运行时存储泛型类型,允许您恢复擦除信息丢失了。
您可以检索这些的实际泛型类型:
这意味着如果你只是一个List类型的对象,那么你无法做到这一点来获得它的通用类型(object.getClass()
会得到你List
而且#&# 39;它) - 它已经永久丢失了。但是,如果您正在尝试找出方法参数或上述任何一种的泛型类型,那么通常使用反射可以。由于您的案例不涉及类型变量或其他复杂情况,因此获得实际类型非常简单:
ParameterizedType listArgument = (ParameterizedType) ClassDeclaringFoo.class.getMethod("foo", List.class).getGenericParameterTypes()[0];
Type listType = listArgument.getActualTypeArguments()[0]; //This will be a Class representing String, the type of the List
如果您有更多参数和地图:
public String foo(Object bar, Map<String, Number> possibleFoos) { ... }
代码类似:
ParameterizedType mapArgument = (ParameterizedType) ClassDeclaringFoo.class.getMethod("foo", Object.class, Map.class).getGenericParameterTypes()[1]; //1 is the index of the map argument
Type keyType = mapArgument.getActualTypeArguments()[0]; //This will be a Class representing String, the type of the Map key
Type valType = mapArgument.getActualTypeArguments()[1]; //This will be a Class representing Number, the type of the Map value
可以安全地假设这也是DWR正在使用的,因为类型是方法参数。
其他列出的案例也有类似的方法:
Class.getMethod(...).getGenericReturnType()
会为您提供真正的返回类型Class.getField(fieldName).getGenericType()
将为您提供该字段的真实类型Class.getGenericSuperClass()
将为您提供真正的超级类型Class.getGenericInterfaces()
将为您提供真正的界面类型允许访问Java 8中引入的AnnotatedType
(泛型类型加上类型用法注释)的等效方法:
Class.getMethod(...).getAnnotatedParameterTypes()
Class.getMethod(...).getAnnotatedReturnType()
Class.getField(fieldName).getAnnotatedType()
Class.getAnnotatedSuperClass()
Class.getAnnotatedInterfaces()
现在,当您的案例与示例中一样简单时,这就是花花公子。 但是,想象一下你的例子是这样的:
public T foo(List<T> possibleFoos) {...}
在这种情况下,getGenericParameterTypes()[0].getActualTypeArguments()[0]
会给你T
,这是无用的。要解决T
所代表的含义,您必须查看类定义,也许还要查看超类,同时跟踪每个类中类型变量的命名方式,因为名称可能不同每个
为了更轻松地使用泛型类型反射,您可以使用一个名为GenTyRef的精彩库,为您完成艰苦的工作,如果您需要AnnotatedType
的支持,您可以使用我的分叉叫GeAnTyRef(两者都在Maven Central)。它们还包括一个类型工厂,它允许您构造(Annotated)Type
的实例,使用普通的Java API无法轻松完成。还有一个方便的super type token实现,允许您获得(Annotated)Type
字面值。
有了这些,您可以使用Java允许的泛型类型执行所有操作,而无需我上面解释过的麻烦:
GenericTypeReflector#getExactParameterTypes( ... )
GenericTypeReflector#getExactReturnType( ... )
GenericTypeReflector#getExactFieldType( ... )
GenericTypeReflector#getExactSuperType( ... )
还有更多的操作,比如确定一个Type
是否是另一个的超类型(类似于Class#isAssignableFrom
但是对于泛型类型),解析特定类型变量等。