Java - initializing a class with type parameters

I had a problem initializing a class with a type parameter. This seems to be a flaw in Java type output, and I would like to know if there is a way about this or a better way to achieve this.

public class ParentModel {} public class ChildModel extends ParentModel {} public class Service<E extends ParentModel, T extends Collection<E>> { private Class<T> classOfT; private Class<E> classOfE; public Service(Class<E> classOfE, Class<T> classOfT) { this.classOfE = classOfE; this.classOfT = classOfT; } } public class BusinessLogic { public void someLogic() { Service<ChildModel, ArrayList<ChildModel>> service = new Service<ChildModel, ArrayList<ChildModel>>(ChildModel.class, ArrayList.class); } } 

A compile-time error is located in BusinessLogic::someLogic() :

Constructor Service <ChildModel, ArrayList <ChildModel → (class <ChildModel>, class <ArrayList>) - undefined

Compiled in Java 7.

+6
source share
2 answers

Since generics are implemented in Java by erasing, there is no Class<ArrayList<ChildModel>>> , only Class<ArrayList> .

What you can do is allow supertypes.

 Class<? super T> classOfT; Class<? super E> classOfE; public Service(Class<? super E> classOfE, Class<? super T> classOfT) { 

alternatively you can do a double class:

 Class<ArrayList<Integer>> clazz = (Class<ArrayList<Integer>>) (Class<? super ArrayList>) ArrayList.class; 

But be careful: the class is simply ArrayList - Java will not perform additional type checks at runtime in generators . See for yourself:

 ArrayList<Integer> a1 = new ArrayList<>(); ArrayList<Double> a2 = new ArrayList<>(); System.out.println(a1.getClass() == a2.getClass()); 

This is the same class. There are practically no generics at run time.

+2
source

Since there is no such thing as ArrayList<ChildModel>.class , there will not be an elegant way to solve this problem. You can pass you the raw type of your constructor, as Yasin mentioned, for example:

 Service<ChildModel, ArrayList<ChildModel>> s1 = new Service<>(ChildModel.class, (Class) ArrayList.class) 

The difference with your call is that here we are using the raw type of Class , while your example uses the type of Class<ArrayList> (so this is not an error).

Another option is to get the type from the actual instance:

 Class<ArrayList<ChildModel>> fromObj = (Class<ArrayList<ChildModel>>) new ArrayList<ChildModel>(0).getClass(); 

This is more verbose, but I would prefer that over the raw type (in both cases you will get compiler warnings)

+1
source

All Articles