Typically, I've seen people use the class literal like this:
Class<Foo> cls = Foo.class;
But what if the type is generic, e.g. List? This works fine, but has a warning since List should be parameterized:
Class<List> cls = List.class
So why not add a <?>
? Well, this causes a type mismatch error:
Class<List<?>> cls = List.class
I figured something like this would work, but this is just a plain ol' syntax error:
Class<List<Foo>> cls = List<Foo>.class
How can I get a Class<List<Foo>>
statically, e.g. using the class literal?
I could use @SuppressWarnings("unchecked")
to get rid of the warnings caused by the non-parameterized use of List in the first example, Class<List> cls = List.class
, but I'd rather not.
Any suggestions?
You can't due to type erasure.
Java generics are little more than syntactic sugar for Object casts. To demonstrate:
List<Integer> list1 = new ArrayList<Integer>();
List<String> list2 = (List<String>)list1;
list2.add("foo"); // perfectly legal
The only instance where generic type information is retained at runtime is with Field.getGenericType()
if interrogating a class's members via reflection.
All of this is why Object.getClass()
has this signature:
public final native Class<?> getClass();
The important part being Class<?>
.
To put it another way, from the Java Generics FAQ:
Why is there no class literal for concrete parameterized types?
Because parameterized type has no exact runtime type representation.
A class literal denotes a
Class
object that represents a given type. For instance, the class literalString.class
denotes theClass
object that represents the typeString
and is identical to theClass
object that is returned when methodgetClass
is invoked on aString
object. A class literal can be used for runtime type checks and for reflection.Parameterized types lose their type arguments when they are translated to byte code during compilation in a process called type erasure . As a side effect of type erasure, all instantiations of a generic type share the same runtime representation, namely that of the corresponding raw type . In other words, parameterized types do not have type representation of their own. Consequently, there is no point in forming class literals such as
List<String>.class
,List<Long>.class
andList<?>.class
, since no suchClass
objects exist. Only the raw typeList
has aClass
object that represents its runtime type. It is referred to asList.class
.