2015-08-06 16 views
5

Qualcuno può spiegare perché compila il seguente pezzo di codice?Confuso da generici in Java

List<Long> longNums = new ArrayList(Arrays.asList("one", "two", "three")); 

È dovuto alla cancellazione del tipo?

se ho il seguente metodo:

public <T> T readProperty(String propName, Class<T> type); 

Come posso fare in modo che restituisca, dire una List<Long> e non un List<String>? Ovviamente, al tipo di chiamata il metodo posso solo fornire List.class e pregare.

//run and pray 
List<Long> longNums = readProperty("prop", List.class); 

è già successo a me che un tale metodo non corretto assegnato un elenco di oggetti stringa in un elenco di numero di lungo, e non è stato fino a quando ho fatto funzionare, che ho visto il ClassCastException.

+6

Semplicemente - Non mescolare farmaci generici con raws. –

+0

Come mai si desidera memorizzare il letterale String nella lista 'Long'? –

+0

non un letterale String, ma un elenco di stringhe. Forse dovrei parafrasare – preslavrachev

risposta

1

vi siete persi diamante <> (questo non verrà compilato):

List<Long> longNums = new ArrayList<>(Arrays.asList("one", "two","three")); 
+1

aae questo non viene nemmeno compilato :) –

+0

@kocko è vero. Ma almeno questo impedirà l'errore di runtime :) – Maroun

+0

Potete aiutarmi a risolvere la seconda parte? – preslavrachev

9

Non si dovrebbe aspettare il programma a comportarsi in modo corretto, perché non si utilizza Generics correttamente.

primo luogo, non si deve mescolare con Generics Raws, il che significa che questa affermazione

List<Long> longNums = new ArrayList(Arrays.asList("one", "two", "three")); 

non è valido (in termini di correttezza). Se fosse:

List<Long> longNums = new ArrayList<Long>(Arrays.asList("one", "two", "three")); 

non sarebbe nemmeno compilare e si dovrebbe ottenere l'errore al momento della compilazione (non a runtime, che può essere più confusa e spaventoso).

Così, al fine di ottenere compilato, l'elenco dovrebbe essere definito come:

List<String> longNums = new ArrayList<>(Arrays.asList("one", "two", "three")); 

Inoltre, con riferimento a questa dichiarazione

//run and pray 
List<Long> longNums = readProperty("prop", List.class); 

c'è in realtà alcun modo per assicurarsi che readProperty sarà restituire List<Long>, quindi sarà necessario eseguire una trasmissione o aggiungere un'annotazione @SuppressWarnings. Il motivo di ciò è la funzione di cancellazione del tipo del compilatore: il tipo parametrizzato Long viene cancellato ed è terminato in Runtime (quando viene eseguito effettivamente lo readProperty() e il valore di prob viene ottenuto tramite Reflection).

+0

Sì, lo so. La prima parte è più di un esempio di illustrazione per la seconda parte. Qual è il modo di risolverlo? – preslavrachev

+0

@ user1107412, ho aggiornato la risposta. –

+0

Grazie. Mi piacerebbe che ci fosse davvero un modo per specificare nei parametri che mi aspetto davvero una lista . Qualcosa come (se esistesse) List .class. Il mio grosso problema è che l'assegnazione funziona senza problemi in fase di esecuzione, e ho appena capito il problema, quando provo ad accedere ad un elemento della lista. Ho provato a trasmettere esplicitamente a (Lista ) ma non sembrava essere di aiuto. – preslavrachev

1

Queste sono due domande separate.

List<Long> longNums = new ArrayList(Arrays.asList("one", "two", "three")); 

Per compatibilità motivi sorgente un raw type è consentito in questi casi. Non dovresti fare affidamento su questo perché, come puoi vedere, sconfigge l'intera idea dei generici.

Per quanto riguarda la seconda domanda, si può eludere il problema facendo qualcosa di simile:

public <T> List<T> readListProperty(String propName, Class<T> type); 
... 
List<Long> longNums = readProperty("prop", Long.class); 

E 'più di una soluzione che una soluzione e non è sempre applicabile.(Ad esempio quando sono necessari tipi di resi ancora più complessi, come Map<String,List<String>>)

+0

Purtroppo non posso toccare la firma del metodo. Inoltre, ho provato il casting esplicito del risultato in List ma questo non ha aiutato neanche. Il compito continua senza problemi. Capisco solo il problema del casting, quando provo ad accedere ad un elemento della lista. – preslavrachev

+0

Questo è sfortunatamente com'è, se non puoi cambiare il metodo, non c'è trucco in fase di compilazione per farti girare. È possibile controllare il risultato manualmente in fase di esecuzione, ma controllare un singolo elemento non è sufficiente, è necessario controllarli tutti perché è possibile che l'elenco conterrà 6 'Long's, seguito da un' String'. – biziclop

0

Se si definisce un elenco come ArrayList, java non sa quale tipo di oggetto ci sia dentro. Puoi assegnarlo a ArrayList<Long>, ma riceverai un errore quando chiami metodi o proprietà sugli oggetti, perché il tipo non corrisponde.

0

classe generica:

public abstract class GenericClass<T> { 

private T managedClass; 
public List<T> readListProp(String propName,T object){ 
    //do stuff using T type instead of Long,String,Double,etc 
} 
Other classes: 
public class FirstClass extends GenericClass<String> 
{... 
//you have a class where T from generic is replaced with String 
} 
public class SecClass extends GenericClass<Double> 
{... 
//you have a class where T from generic is replaced with Double 
} 
+0

Questa risposta sembra non avere nulla a che fare con la domanda. Se lo fa, per favore spiega! – anderas