ParameterizedType.getRawType() returns j.l.r.Type, not Class<?>?
ParameterizedType parameterized =
(ParameterizedType) List.class.getMethod("iterator").getGenericReturnType();
Type raw = parameterized.getRawType();
ParameterizedType#getRawType()
returns a Type
, not a Class<?>
(although I get that java.lang.Class
now implements Type
). Is there a good reason why getRawType()
doesn't declare its return type to be Class<?>
? Are there extreme cases where getRawType()
's result might not be a 开发者_运维技巧Class<?>
?
It's enough of a thrashing to work with j.l.r.Type
as it is; this seems like an instance in which they could have saved us one downcast.
It must return a Class
object, there's no other way.
Why? Who knows, maybe some idealistic bias. If it returned Class
, it would be the only appearance of Class
in the new Type
interfaces.
The real problem is the mixing of Class
and Type
. Previously, all types are represented in Class
. It was already messy, but still tolerable. There weren't very many types.
With the new generic types, they should have designed a cleaner and true-to-specType
hierarchy independent of Class
. Instead they incorporated Class
with Type
and created more mess. The entire hierarchy just doesn't make sense. Anyone new to the subject and unaware of the history will be appalled by this nonsense.
I wouldn't hold the design of Type
to a high standard. For example, ParameterizedType
defines equals()
, but not hashCode()
. There's no way to have two implementations of ParameterizedType
work in one hash map. And wildcard is also a type? Hell no.
And the name of the method getRawType()
is just idiotic. It has nothing to do with raw type
. It should be plainly named getClassOrInterface()
. Would it be too verbose? Look at getActualTypeArguments()
then. (And yeah, it returns actual arguments! Not fake ones!)
I was thinking about this, and I have a hunch. Perhaps they wanted to leave the possibility open for future craziness like this:
public class Z<L extends List<?>> {
L<Double> test;
}
This is not legal Java code, but I think it's clear what it would mean; new Z<ArrayList<?>>().test
would be of type ArrayList<Double>
.
If this were legal, ((ParameterizedType) test.getGenericType()).getRawType()
would return a TypeVariable
.
Sun's implementation of ParameterizedType
has defined the getRawType()
method to return Class<?>
. So it clearly returns only Class<?>
However, on my classpath there are a few more implementations of ParameterizedType
- from hibernate-validator, from aspectj, hibernate-annotations, jaxb. Some of them return Class<?>
, some - Type
. I don't know how they are used though.
There are other uses for the Type interface hierarchy than just the reflection api. For instance, a code generation library may define custom implementations. The JDK 8 itself has 3 different implementations of WildcardType. If ParameterizedType.getRawType() returned a Class instance, then you'd need to be able to create a Class instance whenever you want.
A Class is a very deeply-ingrained-in-the-JVM type that has bindings back to native-managed memory. To create a Class instance, you must have the byte code that defines the class. But in the case of a code generation library, the byte code doesn't even exist yet. If they had required the ParameterizedType to return a Class, it would limit the applicability of the Type interface hierarchy to only the reflection api.
This may not seem like a big deal, but neither is a cast.
ParameterizedType.getOwnerType() returns a Type as it may itself be either a Class or another ParameterizedType. It may in theory return a TypeVariable, as the following is valid Java:
<M extends Map<?,?>> M.Entry<?,?> first(M map) { ... }
However, it's compiled as a static reference to the type variable's erasure, in this case M.Entry would be compiled as Map.Entry. Instead of a TypeVariable, a call to getOwnerType() from the reflection api will be a Class, at least according to my tests.
精彩评论