问题描述
我想请求一个项目集合(特定反射的种类)。但关于类型擦除似乎不可能,也有关于我在堆栈上阅读的一些主题。有一些解决方法(),但我很好奇是否有人知道它是如何完成的例如,DWR:
I would like to request for an item class of collection (kind of specific reflection). But regarding to type erasure it seems not possible and also regarding to some topics I've read here on stack. There are some workarounds (here), but I'm curious if somebody know how is it done for example by DWR:
或者如果有一些更好的解决方法会很棒。
or in case that there is some better workaround it would be great.
假设我们有类似的东西:
Let's say we have something like:
public String foo(List<String> possibleFoos) {
我需要的只是找出参数possibleFoos是字符串列表,而不仅仅是List
and all I need to is find out that parameter possibleFoos is list of Strings, not just List
推荐答案
虽然Java会在运行时擦除类型(因此将列表< String>
转换为列表
),在很多情况下它实际存储了运行时中的泛型类型允许您恢复丢失的信息以进行擦除。
您可以检索这些的实际泛型类型:
While it's true that Java will erase types at runtime (thus turning List<String>
into just List
), in many cases it actually does store the generic type in runtime allowing you to restore the information lost to erasure.You can retrieve the actual generic types for these:
- 方法参数(您的情况)
- 方法返回类型
- 字段类型
- 超级类/接口
- Method arguments (your case)
- Method return types
- Field types
- Super classes/interfaces
这意味着如果你只是一个List类型的对象,你就无法做到它的泛型类型( object.getClass()
将得到你列出
就是这样) - 它已经永久丢失了。但是,如果您试图找出方法参数或上述任何一种的泛型类型,那么通常使用反射可以。由于您的情况不涉及类型变量或其他复杂情况,因此获取实际类型非常简单:
This means if you simply have an object of type List, there's nothing you can do to get it's generic type (object.getClass()
will get you List
and that's it) - it's been permanently lost. But, if you're trying to figure out the generic type for a method argument or any of the above, you usually can by using reflection. As your case doesn't involve type variables or other complications, it's pretty straightforward to get the actual type:
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
如果您有更多的参数而改为地图:
If you had a more parameters and a map instead:
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正在使用的,因为类型是方法参数。
It's safe to assume this is what DWR is using as well, as the types are method arguments.
类似的方法可用于其他列出的情况:
Similar methods are available for other listed cases:
-
Class.getMethod(...)。getGenericReturnType()
将为您提供真实的返回类型 -
Class.getField(fieldName).getGenericType()
将为您提供该字段的真实类型 -
Class.getGenericSuperClass()
将为您提供真正的超级类型 -
Class.getGenericInterfaces()
将为您提供真实的界面类型
Class.getMethod(...).getGenericReturnType()
will get you the real return typeClass.getField(fieldName).getGenericType()
will get you the real type of the fieldClass.getGenericSuperClass()
will get you the real super typeClass.getGenericInterfaces()
will get you the real interface types
存在允许访问(通用类型加上关于类型用法的注释)在Java 8中引入:
Equivalent methods exist allowing access to AnnotatedType
(generic type plus annotations on the type usage) introduced in Java 8:
-
Class.getMethod(...)。getAnnotat edParameterTypes()
-
Class.getMethod(...)。getAnnotatedReturnType()
-
Class.getField(fieldName).getAnnotatedType()
-
Class.getAnnotatedSuperClass ()
-
Class.getAnnotatedInterfaces()
Class.getMethod(...).getAnnotatedParameterTypes()
Class.getMethod(...).getAnnotatedReturnType()
Class.getField(fieldName).getAnnotatedType()
Class.getAnnotatedSuperClass()
Class.getAnnotatedInterfaces()
现在,当你的情况像示例中一样简单时,这就是花花公子。
但是,想象一下你的例子是这样的:
Now, this is all dandy when your case as simple as in the example.But, imagine if your example looked like this:
public T foo(List<T> possibleFoos) {...}
在这种情况下, getGenericParameterTypes()[0] .getActualTypeArguments ()[0]
会给你 T
这是无用的。要解决 T
代表什么,你必须查看类定义,也许是超类,同时跟踪每个类中类型变量的命名方式,因为每个名称可能不同。
In this case, getGenericParameterTypes()[0].getActualTypeArguments()[0]
would give you T
which is rather useless. To resolve what T
stands for, you'd have to look into the class definition, and perhaps super classes, while keeping track of how the type variables are named in each class, as the names could be different in each.
为了更容易地使用泛型类型反射,你可以使用一个名为为您付出的努力,如果您需要支持 AnnotatedType
s,你可以使用名为的分叉(两者都在Maven Central中)。它们还包括一个类型工厂,它允许您构造(Annotated)Type
的实例,使用普通的Java API无法轻松完成。还有一个方便的实现,让您获得(带注释)类型
literal。
To make working with generic type reflection easier, you can use a wonderful library called GenTyRef that does the hard work for you, and if you need support for AnnotatedType
s, you can use my fork called GeAnTyRef (both are in Maven Central). They also include a type factory, that allows you to construct instances of (Annotated)Type
, which you can not easily do using normal Java API. There's also a handy super type token implementation allowing you to get an (Annotated)Type
literal.
有了这些,您可以使用Java允许的泛型类型,而不会有麻烦我在上面解释过:
With those, you can do everything with generic types that Java allows without the hassle I explained above:
-
GenericTypeReflector#getExactParameterTypes(...)
-
GenericTypeReflector#getExactReturnType(...)
-
GenericTypeReflector#getExactFieldType( ...)
-
GenericTypeReflector#getExactSuperType(...)
GenericTypeReflector#getExactParameterTypes( ... )
GenericTypeReflector#getExactReturnType( ... )
GenericTypeReflector#getExactFieldType( ... )
GenericTypeReflector#getExactSuperType( ... )
还有更多的操作,比如确定一个 Type
是否是另一个的超类型(类似于 Class#isAssignableFrom
但是对于泛型类型),解析特定的类型变量等。
And many more operations, like figuring out if one Type
is a super type of another (similar to Class#isAssignableFrom
but for generic types), resolving specific type variables etc.
这篇关于DWR如何转换传入数据并规避类型擦除的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!