Reputation: 13986
I have a method that returns a type that it is given:
T foo(Class<T> valueType) {...};
String s = foo(Java.lang.String.class);
I'm trying to send a generic type as my class, but getting compiler errors. For example, let's say I want to return an ArrayList of Strings:
ArrayList<String> list = foot(ArrayList<String>.class)
the parameter "String" is giving errors. Is there anyway I can specify the generic type to return?
Upvotes: 2
Views: 2503
Reputation: 4571
Assuming you are here only concerned about static types, this trick might be useful:
@SuppressWarnings("unchecked")
public static <T>
Class<T> appropriateClass(T... args) {
return (Class<T>) args.getClass().getComponentType();
}
Class<ArrayList<String>> c = appropriateClass();
ArrayList<String> list = foo(c);
Actually I am not very proud of the trick. But you might want to give it a try.
If you test it:
System.out.println(c); // prints "class java.util.ArrayList"
So it is equivalent to an ugly cast like (Class<ArrayList<String>>) (Class<?>) ArrayList.class
.
If you actually need to have different tokens for ArrayList<String>
and ArrayList
at runtime, you should use the TypeToken
technique as mentioned by Sean Patrick Floyd.
Upvotes: 0
Reputation: 13914
Type Erasure rears its ugly head. Essentially, Java does compile-time checking on the generic <…>
clauses, then erases them from the run-time objects, losing the information forever. Nasty, eh? Since .class
metaobjects are referenced at run-time, they suffer from the erasure as well.
ArrayList<String>.class
is Erased at compile-time, to be ArrayList.class
.
If you want type-safety with the generics, you'll have to pass in two parameters, e.g.
ArrayList<String> foo = foot(ArrayList.class, String.class)
Upvotes: 0
Reputation: 122489
Just cast the input or output of the method:
ArrayList<String> list = foot((Class<ArrayList<String>>)(Class<?>)ArrayList.class);
or
ArrayList<String> list = (ArrayList<String>)foot(ArrayList.class);
Basically, the Class
class does not work well with generics, because it represents a runtime thing, whereas generics works at compile time. At runtime, there is just one class object for ArrayList
in the program. Even if you call it Class<ArrayList<String>>
or Class<ArrayList<Integer>>
or Class<ArrayList>
, it's still the same single object. So what type should it be? There's no simple answer that works for everything.
The Java language decided that the class literal ArrayList.class
should just have the type Class<ArrayList>
. But that causes problems when you want an expression of type Class<ArrayList<String>>
, so you have to bend the types.
Upvotes: 0
Reputation: 41911
Would this work for you(edited)?
ArrayList list = foot(ArrayList.class)
Upvotes: 0
Reputation: 32296
The runtime class
field value does not depend on the generic type you apply, and this syntax is illegal. More on this here.
Upvotes: 1