2016-03-13 10 views
6

Ich habe ein Problem beim Initialisieren einer Klasse mit Typparameter. Es scheint ein Mangel an Java-Typ-Schlussfolgerung zu sein und ich würde gerne wissen, ob es einen Weg gibt, um dies zu erreichen oder einen besseren Weg, dies zu erreichen.Java - initialisierende Klasse mit Typparametern ausgeben

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); 
    } 
} 

Kompilierzeitfehler ist in BusinessLogic::someLogic():

Der Konstruktor Dienst < ChildModel, Arraylist < ChildModel >> (Klasse < ChildModel> Klasse < Arraylist>) nicht definiert ist

Kompiliert mit Java 7.

+0

Sie beabsichtigen, 'Klassen'-Felder oder -Felder von welchem ​​Typ auch immer' T' und 'E' zu haben? –

Antwort

2

Da Generika in Java "durch Löschen" implementiert sind, gibt es keine Class<ArrayList<ChildModel>>>, nur eine Class<ArrayList>.

Sie können Supertypen zulassen.

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

alternativ können Sie doppelt werfen die Klasse:

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

Aber Vorsicht: die Klasse ist nur ArrayList - Java keine zusätzlichen Typüberprüfungen zur Laufzeit auf den Generika führen. Überzeugen Sie sich selbst:

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

Es ist die gleiche Klasse. Zur Laufzeit sind die Generika praktisch verschwunden.

+0

diese 'Klasse > clazz = (Klasse >) ArrayList.class;' sollte nicht kompilieren, oder? Ich mag die Idee, 'Super' zu verwenden, obwohl – nyname00

+0

Sorry, Sie brauchen eine Doppel-Besetzung, mit entweder' Super' oder 'extends'. –

1

Da gibt es keine su ch Ding wie ArrayList<ChildModel>.class wird es keine elegante Möglichkeit, dies zu lösen. Sie können einen rohen Typ Sie Ihren Konstruktor übergeben, wie Yassin erwähnt, wie folgt aus:

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

Der Unterschied zu Ihrem Aufruf ist hier, dass wir die rohe Art verwenden Class, während in in Ihrem Beispiel die Typ Class<ArrayList> wird verwendet (dies ist also kein Fehler).

würde Eine andere Möglichkeit, die Art von einer tatsächlichen Instanz zu erhalten:

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

Diese ausführlicher ist, aber ich würde über die rohe Art bevorzugen, dass (in beiden Fällen Sie Compiler-Warnungen erhalten wird)