2016-03-13 4 views
6

Je rencontre un problème lors de l'initialisation d'une classe avec un paramètre de type. Cela semble être une lacune de l'inférence de type Java et j'aimerais savoir s'il existe un moyen de contourner cela ou un meilleur moyen d'y parvenir.Java - Classe d'initialisation de problème avec les paramètres de type

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

erreur de compilation est BusinessLogic::someLogic():

Le constructeur service < ChildModel, ArrayList < ChildModel >> (classe < ChildModel>, classe < ArrayList>) est définie

Compilé en Java 7.

+0

Vous aviez l'intention d'avoir des champs 'Class' ou des champs de tout type' T' et 'E'? –

Répondre

2

Parce que les génériques en Java sont implémentés "par effacement", il n'y a pas de Class<ArrayList<ChildModel>>>, seulement un Class<ArrayList>.

Ce que vous pouvez faire est de permettre les supertypes.

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

alternativement, vous pouvez double-Cast la classe:

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

Mais méfiez-vous: la classe est juste ArrayList - Java ne sera pas effectuer des contrôles de type supplémentaires lors de l'exécution sur les génériques. Voyez vous-même:

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

Il est la même classe. Au moment de l'exécution, les génériques ont quasiment disparu

+0

this 'Class > clazz = (Classe >) ArrayList.class;' ne devrait pas compiler, n'est-ce pas? J'aime l'idée d'utiliser 'super' si – nyname00

+0

Désolé, vous avez besoin d'une double distribution, avec' super' ou 'extends'. –

1

Puisqu'il n'y a pas de su Ch chose comme ArrayList<ChildModel>.class il n'y aura pas de manière élégante de résoudre ce problème. Vous pouvez passer un type brut pour vous votre constructeur, comme mentionné par Yassin, comme ceci:

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

La différence à votre appel est que ici nous utilisons le type brut Class, alors que dans votre exemple le type Class<ArrayList> est utilisé (donc ce n'est pas un bug).

Une autre option serait d'obtenir le type d'une instance réelle:

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

Ceci est plus bavard, mais je préférerais que sur le type brut (dans les deux cas, vous obtiendrez des avertissements du compilateur)