Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get class with generics types in Java

Tags:

java

generics

I am trying to make a method call like this,

public class GenericsTest<T> {

    public static <T> Map<String, T> createMap(Class<? extends Map<String, T>> clazz) {
        return null;
    }

    public static void main(String[] argv) {
        Map<String, Integer> result = createMap(TreeMap.class);
    }
}

But I am getting this error,

<T>createMap(java.lang.Class<? extends java.util.Map<java.lang.String,T>>) in test.GenericsTest<T> cannot be applied to (java.lang.Class<java.util.TreeMap>)

How to fix this problem?

like image 679
ZZ Coder Avatar asked Jul 19 '12 04:07

ZZ Coder


1 Answers

Map<String, Integer> instance = new TreeMap<String, Integer>();

@SuppressWarnings("unchecked")
Map<String, Integer> map =
    createMap((Class<? extends Map<String, Integer>>)instance.getClass());

map.put("x", 1);

System.out.println("THIS IS x: " + map.get("x"));

This will appropriately print out 1. The implementation of the method is most likely

try
{
    return clazz.newInstance();
}
catch (Exception e)
{
    throw new RuntimeException(e);
}

A better implementation of their API would be for them to ask you for the type, T, and for them to give back a Map of their choosing instead of asking you for all of the details. Otherwise, as long as they are not filling in the Map with any data, you can instantiate a Map with the generic type argument yourself like so:

public static <T> Map<String, T> getMap()
{
    return new TreeMap<String, T>();
}

You can then access that without a warning:

// note the lack of type arguments, which are inferred
Map<String, Integer> instance = getMap();

// alternatively, you could do it more explicitly:
// Map<String, Integer> instance = ClassName.<Integer>getMap();

There's really no reason for them to ask you for the Class type of your Map except to give you back an exact match to the implementation (e.g., if you stick in a HashMap, then you will get back a HashMap, and if you stick in a TreeMap, then you will get back a TreeMap). However, I suspect that the TreeMap will lose any Comparator that it was constructed with, and since that is an immutable (final) field of TreeMap, then you cannot fix that; that means that the Map is not the same in that case, nor is it likely to be what you want.

If they are filling in the Map with data, then it makes even less sense. You could always pass in an instance of a Map to fill, or have them return a Map that you can simply wrap (e.g., new TreeMap<String, Integer>(instance);), and they should know which Map offers the most utility to the data.

like image 169
pickypg Avatar answered Oct 04 '22 04:10

pickypg