views:

298

answers:

4

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' a 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?

Thanks!

+7  A: 
cletus
Aha! This makes more sense. I figured that the class literal on a generic wouldn't even make much sense, but I had no idea that it was due to this. Thanks!
Tom
Not sure why someone downvoted this...
cletus
+2  A: 

To expound on cletus' answer, at runtime all record of the generic types is removed. Generics are processed only in the compiler and are used to provide additional type safety. They are really just shorthand that allows the compiler to insert typecasts at the appropriate places. For example, previously you'd have to do the following:

List x = new ArrayList();
x.add(new SomeClass());
Iterator i = x.iterator();
SomeClass z = (SomeClass) i.next();

becomes

List<SomeClass> x = new ArrayList<SomeClass>();
x.add(new SomeClass());
Iterator<SomeClass> i = x.iterator();
SomeClass z = i.next();

This allows the compiler to check your code at compile-time, but at runtime it still looks like the first example.

Jim Garrison
Thanks for the additional explanation--my understanding of generics is so much clearer now that I realize they're not a runtime mechanism. :)
Tom
+1  A: 

There are no Class literals for parameterized types, however there are Type objects that correctly define these types.

See java.lang.reflect.ParameterizedType - http://java.sun.com/j2se/1.5.0/docs/api/java/lang/reflect/ParameterizedType.html

Google's Gson library defines a TypeToken class that allows to simply generate parameterized types and uses it to spec json objects with complex parameterized types in a generic friendly way. In your example you would use:

Type typeOfListOfFoo = new TypeToken<List<Foo>>(){}.getType()

I intended to post links to the TypeToken and Gson classes javadoc but Stack Overflow won't let me post more than one link since I'm a new user, you can easily find them using Google search

Santi P.
A: 

Due to the exposed fact that Class literals doesn't have generic type information, I think you should assume that it will be impossible to get rid of all the warnings. In a way, using Class is the same as using a collection without specifying the generic type. The best I could come out with was:

private <C extends A<C>> List<C> getList(Class<C> cls) {
    List<C> res = new ArrayList<C>();
    // "snip"... some stuff happening in here, using cls
    return res;
}

public <C extends A<C>> List<A<C>> getList() {
    return getList(A.class);
}
Morgaelyn