简体   繁体   中英

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> . 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.

Using reflection one can see that the List has an actualTypeArgument which is ReferenceRange<T> . Since reflection uses class information, I would not expect it to give me ReferenceRange<DvQuantity> . However, when I created the class containing this method, I passed the DvQuantity type as T . So the type filling in T should be available to Java runtime, but I could not find a way of getting it. I end up with a TypeVariableImpl object accessed via reflection, which does not seem to contain any useful data.

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 .

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. 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:

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.

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.

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. If you truly need to raw type of the object, I'd reconsider using generics.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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