Java generics: how do I specify a class type for generic types?
I have a POJO specified as: MyClass < U >, where u is a generic type parameter
This method is implemented as follows:
static void populateMap(Map<String,T> map,Class<T> type) { ... // Parses into the specified type and returns an object of that type. T obj = parse(...,type); map.put (key,obj); ... return map; }
It's compiled In my caller, I try to populate the map with any MyClass instance (regardless of type) as a value So I use the following code:
// Loses type information Map<String,MyClass<?>> m = new HashMap<>(); populateMap(m,MyClass.class);
This does not compile Compilation error:
How can I solve this problem?
Solution
In this case, for class < MyClass > It should be safe to cast unchecked:
// This is okay because we're switching to a type with an unbounded wildcard - // the behaviors of Class.newInstance and Class.cast are still safe. @SuppressWarnings("unchecked") Class<MyClass<?>> classWithNarrowedType = (Class<MyClass<?>>)(Class<?>)MyClass.class; populateMap(m,classWithNarrowedType);
This is a very important solution, especially if you have many calling websites like this, but do not solve the fact that class text is parameterized with the original type, so that they are used as factories of parameterized types, such as MyClass < T >, which is inherently embarrassing
A possible clearer solution is to separate the use of populatemap from class text:
interface Parser<T> { T parse(); } static void populateMap(Map<String,Parser<T> parser) { ... } ... Map<String,MyClass<?>> m = new HashMap<>(); Parser<MyClass<?>> myClassParser = new Parser<MyClass<?>>() { @Override public MyClass<?> parse() { return parse(...,MyClass.class); } }; populateMap(m,myClassParser);
In addition, I recommend using more flexible signatures (see what is PECS (producer extensions consumer super)? For details):
static void populateMap(Map<String,? super T> map,Parser<T> parser)