简体   繁体   English

Java:在嵌套参数化类型中获取内部类型(反射)

[英]Java: getting inner type in nested parameterized types (reflection)

Most of the documentation regarding type erasure handling in Java assumes that the use case is handling a type like SomeType<ParamType> . 关于Java中类型擦除处理的大多数文档都假定用例正在处理类似SomeType<ParamType>的类型。 I am trying to process method parameter for the following method: 我正在尝试处理以下方法的方法参数:

public void setOtherReferenceRanges(List<ReferenceRange<T>> referenceRanges)

When the container class is instantiated with a type DvQuantity, this signature should become public void setOtherReferenceRanges(List<ReferenceRange<DvQuanitity>> referenceRanges) in runtime. 当使用类型DvQuantity实例化容器类时,此签名应在运行时变为public void setOtherReferenceRanges(List<ReferenceRange<DvQuanitity>> referenceRanges)

Using reflection one can see that the List has an actualTypeArgument which is ReferenceRange<T> . 使用反射可以看到List有一个actualTypeArgument ,它是ReferenceRange<T> Since reflection uses class information, I would not expect it to give me ReferenceRange<DvQuantity> . 由于反射使用类信息,我不希望它给我ReferenceRange<DvQuantity> However, when I created the class containing this method, I passed the DvQuantity type as T . 但是,当我创建包含此方法的类时,我将DvQuantity类型作为T传递。 So the type filling in T should be available to Java runtime, but I could not find a way of getting it. 所以T的类型填充应该可用于Java运行时,但我找不到获取它的方法。 I end up with a TypeVariableImpl object accessed via reflection, which does not seem to contain any useful data. 我最终得到了一个通过反射访问的TypeVariableImpl对象,它似乎不包含任何有用的数据。

Can you think of any ways to discover this information in runtime? 你能想到在运行时发现这些信息的方法吗?

When you say 当你说

when I created the class containing this method 当我创建包含此方法的类时

I guess you mean when you create an object of that type, for example: 我猜你的意思是当你创建一个这种类型的对象时,例如:

foo = new ContainerClass<DvQuantity>();

In that case, because of erasure, there is no way to recover the type DvQuantity . 在这种情况下,由于擦除,无法恢复类型DvQuantity

However, if you create a class passing a type parameter to the superclass, like this 但是,如果你创建一个传递一个类型参数的超类,像这样

class DvQuantityContainerClass extends ContainerClass<DvQuantity> {...}
...
foo = new DvQuantityContainerClass();

Or, shorter, an inline anonymous subclass (which looks almost like the first example but with a subtle but important difference): 或者,更短,一个内联匿名子类(看起来几乎像第一个例子,但有一个微妙但重要的区别):

foo = new ContainerClass<DvQuantity>(){};

Then you can recover the type parameter, because you recover the type parameter used to extend a superclass at runtime. 然后,您可以恢复type参数,因为您恢复了用于在运行时扩展超类的类型参数。 Unfortunately, Java itself doesn't provide an easy way to now get the type of the DvQuantityContainerClass.setOtherReferenceRanges method with the T filled in. For that, I've written gentyref , to do advanced reflection on generic types: 遗憾的是,Java本身并没有提供一种简单的方法来获得填充了TDvQuantityContainerClass.setOtherReferenceRanges方法的类型。为此,我编写了gentyref ,对泛型类型进行高级反射:

Method m = DvQuantityContainerClass.class.getMethod("setOtherReferenceRanges", List.class);
// this will return List<ReferenceRange<DvQuanity>>, like you are lookingn for
return GenericTypeReflector.getExactParameterTypes(m, DvQuantityContainerClass.class)

Generic type information is erased by the compiler and is not available at runtime. 通用类型信息由编译器擦除,在运行时不可用。 When I need to ensure a certain type at runtime I pass in a class argument: 当我需要在运行时确保某种类型时,我传入一个类参数:

public <T> void doSomething(T t, Class<T> c);

This is not always convenient or even possible, but for many cases it is possible. 这并不总是方便甚至可能,但在许多情况下它是可能的。

So the type filling in T should be available to Java runtime, but I could not find a way of getting it. 所以T中的类型填充应该可用于Java运行时,但我找不到获取它的方法。

Perhaps it's not entirely correct, but the way I think about it is that at runtime there is no actual class - just an object without a specific type which meets the interface of T. In other words, erasure happens not with objects, but instead with these nebulous (in the OOP world at least) type-things. 也许它并不完全正确,但我想到的方式是在运行时没有实际的类 - 只是没有特定类型的对象满足T的接口。换句话说,擦除不是用对象发生的,而是用这些模糊的(至少在OOP世界中)类型的东西。

http://java.sun.com/docs/books/tutorial/java/generics/erasure.html http://java.sun.com/docs/books/tutorial/java/generics/erasure.html

There are ways of capturing the type information inside the class itself (T types would need a method getUnderlyingType()... or something), but that's a bad idea. 有一些方法可以捕获类本身内部的类型信息(T类型需要一个方法getUnderlyingType()...或者其他东西),但这是一个坏主意。 If you truly need to raw type of the object, I'd reconsider using generics. 如果你真的需要原始类型的对象,我会重新考虑使用泛型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM