I feel utterly silly for having to ask this, but I'm failing to understand why doesn't the following Java code compile:
void <T> doSomething(List<T> items) {
Class<? extends T> clazz = items.get(0).getClass();
...
}
From Java doc:
The actual result type is Class< ? extends |X|> where |X| is the erasure of the static type of the expression on which getClass is called. For example, no cast is required in this code fragment:
Number n = 0; Class< ? extends Number> c = n.getClass();
EDIT:
Found this nice explanation of what erasure of the static type means.
There's a way to preserve generic type information using subclasses, known as super type token. A now deleted answer helpfully pointed out that Guava library has a convenient utility for exploiting this.
Here's a great article on extracting generic types reflectively and a nice lib, called GenTyRef, simplifying it
I forked GenTyRef to add support for working with AnnotatedType
s (introduced in Java 8). It's called GeantyRef (and it's in Maven Central)
Now you can retrieve the type of T at runtime: Type mySuperclass = myFoo. getClass(). getGenericSuperclass(); Type tType = ((ParameterizedType)mySuperclass).
The short answer is, that there is no way to find out the runtime type of generic type parameters in Java. A solution to this is to pass the Class of the type parameter into the constructor of the generic type, e.g.
In Java there's a single metaclass: Class . Its instances (only one per type exists) are used to represent classes and interfaces, therefore the T in Class<T> refers to the type of the class or interface that the current instance of Class represents.
T is type parameters (also called type variables); delimited by angle brackets (<>), follows the class name. T is just a symbol, like a variable name (can be any name) declared during writing of the class file.
The erasure of the static type of items.get(0)
is Object
(since T
is erased during compilation).
Therefore items.get(0).getClass()
returns a Class<? extends Object>
, not a Class<? extends T>
, which explains why your attempted assignment fails.
This will pass compilation :
Class<? extends Object> clazz = items.get(0).getClass();
If you want the Class
of the generic parameter to be known by that method, you can pass it as an additional argument.
void doSomething(List<T> items, Class<T> clazz) {
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With