Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I return a list of a certain type when calling a generic method that accepts a Class<T> and returns a T?

I'm calling a method from a library with this signature:

public <T> T get(Class<T> c)

And I'd like to get a List<MyClass> as a return value. But calling it like this does not compile ("Cannot select from parameterized type"):

List<MyClass> myClasses = get(List<MyClass>.class);

This compiles, but gives a warning:

List<MyClass> myClasses = get(List.class);

The warning says "Unchecked Assignment". How can I avoid this warning and avoid casting my list?

like image 747
Daniel Kaplan Avatar asked May 13 '13 20:05

Daniel Kaplan


People also ask

How do I get a class instance of generic type T?

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.

Can a method return a list in Java?

The list() method of java. util. Collections class is used to return an array list containing the elements returned by the specified enumeration in the order they are returned by the enumeration.

Can a method return a generic type?

Just like type declarations, method declarations can be generic—that is, parameterized by one or more type parameters.


2 Answers

You are using generics here, so the underlying type of item in the list has been erased at runtime and the compiler knows it can't check it for you at compile time thus the warning. If you use a generic type here you won't be able to avoid the warning. You can suppress it if you know for sure that the cast you are doing won't lead to an exception.

@SuppressWarnings("unchecked")
like image 184
cmbaxter Avatar answered Oct 14 '22 06:10

cmbaxter


Note: I post this more as a point of interest than as a recommended answer. You're generally better off simply suppressing warnings.

If you really hate suppressing warnings but you also hate seeing the warnings, there is a hacky alternative to the accepted answer. You can instantiate an archetype object, such as ArrayList<MyClass>, and then pass archetype.getClass() into the generic method instead of List.class as done in the example and the accepted answer.

This would look like:

ArrayList<MyClass> archetype = new ArrayList<>();
List<MyClass> myClasses = get(archetype.getClass());

One obvious drawback here is the unnecessary cost of instantiating the archetype object, but this can be mitigated somewhat by making it a static instance. A bigger drawback, in my estimation, is that you have to use a concrete class as your archetype, which can be needlessly limiting.

like image 23
Mark McClelland Avatar answered Oct 14 '22 08:10

Mark McClelland