2016-03-13 6 views
6

Sto riscontrando un problema durante l'inizializzazione di una classe con parametro di tipo. Sembra essere una lacuna dell'inferenza di tipo di Java e vorrei sapere se c'è un modo per aggirare questo o un modo migliore per raggiungere questo obiettivo.Java - Classe di inizializzazione del problema con i parametri del tipo

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

errore di compilazione è in BusinessLogic::someLogic():

Il costruttore servizio < ChildModel, ArrayList < ChildModel >> (Class < ChildModel>, classe < ArrayList>) non è definito

Compiled to Java 7.

+0

Ate intendevi avere campi 'Class' o campi di qualunque tipo' T' e 'E' sono? –

risposta

2

Poiché i generici in Java sono implementati "per cancellazione", non esiste lo Class<ArrayList<ChildModel>>>, solo uno Class<ArrayList>.

Quello che puoi fare è consentire i supertipi.

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

In alternativa, è possibile fare doppio-cast della classe:

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

Ma attenzione: la classe è appena ArrayList - Java non effettuerà controlli di tipo aggiuntivi in ​​fase di esecuzione sui farmaci generici. Guardate voi stessi:

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

E è stessa classe. In fase di runtime, i generici sono praticamente scomparsi

+0

questo 'Classe > clazz = (Classe >) ArrayList.class;' non deve essere compilato, vero? Mi piace l'idea di usare 'super' anche se – nyname00

+0

Spiacente, hai bisogno di un doppio cast, con' super' o 'extends'. –

1

Dato che non c'è su ch cosa come ArrayList<ChildModel>.class non ci sarà un modo elegante per risolvere questo. È possibile passare un tipo grezzo a voi il vostro costruttore, come detto da Yassin, in questo modo:

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

La differenza per la vostra invocazione è che qui stiamo usando il tipo grezzo Class, mentre nel nel tuo esempio la viene utilizzato il tipo Class<ArrayList> (quindi questo non è un bug).

Un'altra opzione sarebbe quella di ottenere il tipo da un caso reale:

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

Questo è più prolisso, ma preferirei che il tipo di prima (in entrambi i casi si otterrà avvisi del compilatore)

Problemi correlati