Question

Since generics were introduced, Class is parametrized, so that List.class produces Class<List>. This is clear.

What I am not able to figure out is how to get a instance of Class of type which is parametrized itself, i.e. Class<List<String>>. Like in this snippet:

public class GenTest {
    static <T> T instantiate(Class<T> clazz) throws Exception {
        return clazz.newInstance();
    }
    public static void main(String[] args) throws Exception {
        // Is there a way to avoid waring on the line below
        // without using  @SuppressWarnings("unchecked")?
        // ArrayList.class is Class<ArrayList>, but I would like to
        // pass in Class<ArrayList<String>>
        ArrayList<String> l = GenTest.instantiate(ArrayList.class);
    }
}

I run into variations of this problem quite often and I still don't know, if I just miss something, or if there is really no better way. Thanks for suggestions.

Was it helpful?

Solution

The Class class is a run-time representation of a type. Since parametrized types undergo type erasure at runtime, the class object for Class would be the same as for Class<List<Integer>> and Class<List<String>>.

The reason you cannot instantiate them using the .class notation is that this is a special syntax used for class literals. The Java Language Specification specifically forbids this syntax when the type is parametrized, which is why List<String>.class is not allowed.

OTHER TIPS

Classes represent classes loaded by a class loader, which are raw types. To represent a parameterized type, use java.lang.reflect.ParameterizedType.

I don't think that you can do what you are trying. Firstly, your instantiate method doesn't know that its dealing with a parameterised type (you could just as easily pass it java.util.Date.class). Secondly, because of erasure, doing anything particularly specific with parameterised types at runtime is difficult or impossible.

If you were to approach the problem in a different way, there are other little tricks that you can do, like type inference:

public class GenTest
{
    private static <E> List<E> createList()
    {
        return new ArrayList<E>();
    }

    public static void main(String[] args)
    {
        List<String> list = createList();
        List<Integer> list2 = createList();
    }
}

The only thing you can do is instantiate List<String> directly and call its getClass():

instantiate(new List<String>() { ... }.getClass());

For types with multiple abstract methods like List, this is quite awkward. But unfortunately, calling subclass constructors (like new ArrayList<String>) or factory methods (Collections.<String>emptyList()) don't work.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top