2015-05-18 5 views
7

mi sono imbattuto nel seguente codice, un semplice esempio di aggiunta di elementi di ListArrayList <Integer> consente l'aggiunta di stringhe?

List list = new ArrayList<Integer>(); 
    ListIterator<Integer> litr = null; 
    list.add("A"); 

    list.add("1"); 

    list.add(5); 

    litr = list.listIterator(); 
    while(litr.hasNext()){ 
     System.out.println("UIterating " + litr.next()); 
    } 

mi aspettavo di gettare un ClassCastException, ma piuttosto ha scritto questo alla console

A 
1 
5 

che sembra strano . Quando ho provato:

List<Integer> list = new ArrayList<Integer>(); 

Ho ottenuto un errore in fase di compilazione.

Le sarei grato se qualcuno potrebbe spiegare come gli String oggetti vengono aggiunti al ArrayList

+4

http://stackoverflow.com/questions/339699/java-generics-type-erasure-when-and-what-happens – CupawnTae

+4

http://stackoverflow.com/questions/2770321/what-is-a-raw -type-and-why-shouldnt-we-use-it – Reimeus

+1

Posso riassumerlo in una frase: "In Java, i generici vengono eseguiti solo in fase di compilazione". Detto questo, Java ti lancia un avvertimento sull'utilizzo dei tipi non elaborati per questo motivo. – Powerlord

risposta

4

assegnato il nuovo ArrayList a un elenco non tipizzato. Le restrizioni di tipo generico non si applicano a un elenco non tipizzato, ti consentirà di inserire tutto ciò che desideri. Il compilatore non tiene traccia del fatto che la tua lista non tipizzata si riferisce a qualcosa che è stato dichiarato con un tipo generico.

In ogni caso questo non produrrebbe un ClassCastException, i generici influiscono solo sulla compilazione. In fase di esecuzione

Il caso in cui si inserisce il tipo sulla variabile di lista:

List<Integer> list = new ArrayList<Integer>(); 

è preferito, si dovrebbe generare un errore di compilazione che ti dice che stai mettendo il tipo sbagliato nella collezione.

C'è una descrizione di come l'eredità, il codice non generico e codice generico interoperare in this article:

In corretto codice generico, Collezione sarebbe sempre essere accompagnati da un parametro di tipo. Quando un tipo generico come Collection viene utilizzato senza un parametro type, viene chiamato un tipo raw.

Il primo istinto della maggior parte delle persone è che la raccolta significa davvero Collection<Object>. Tuttavia, come abbiamo visto in precedenza, non è sicuro passare uno Collection<Part> in un luogo in cui è richiesto un Collection<Object>. È più accurato dire che il tipo Collection denota una collezione di un tipo sconosciuto, proprio come Collection<?>.

Ma aspetta, anche questo non può essere giusto! Prendere in considerazione la chiamata a getParts(), che restituisce una raccolta. Questo viene quindi assegnato a k, che è un Collection<Part>. Se il risultato della chiamata è un Collection<?>, l'assegnazione sarebbe un errore.

In realtà, l'assegnazione è legale, ma genera un avviso non controllato. L'avvertimento è necessario, perché il fatto è che il compilatore non può garantire la sua correttezza. Non abbiamo modo di verificare il codice precedente in getAssembly() per garantire che la raccolta restituita sia effettivamente una raccolta di parti. Il tipo utilizzato nel codice è Collection e uno potrebbe legalmente inserire tutti i tipi di oggetti in una tale raccolta.

Quindi, questo non dovrebbe essere un errore? In teoria, sì; ma in pratica, se il codice generico sta per chiamare il codice legacy, questo deve essere consentito. Spetta a te, programmatore, accertarti che in questo caso il compito è sicuro perché il contratto di getAssembly() dice che restituisce una collezione di Parti, anche se la firma del tipo non lo mostra.

+0

Solo una FYI: dovresti mettere i blocchi di codice attorno al codice nella citazione. Altrimenti, non è possibile vedere che una delle raccolte è 'Collezione ' – Powerlord

+0

@Powerlord: giusto, grazie –

+0

@NathanHughes Grazie per la risposta. Ho un'idea dell'elenco non tipizzato e della raccolta non elaborata –

1

Ciò è possibile a causa di come i generici sono implementate in Java - utilizzando type erasure, e perché Java supporta raw types per la compatibilità con le vecchie versioni di Java (1.4 e precedenti).

I generici esistono solo nel codice sorgente. Il compilatore li usa per controllare i tipi in fase di compilazione, ma poi getta via i generici. A runtime, un List<Integer> è solo un di oggetti e non sa che si tratta di un elenco che dovrebbe contenere solo oggetti Integer.

Java supporta l'utilizzo di tipi non elaborati come List anziché List<Integer> per compatibilità con le versioni precedenti. Quando si utilizza un tipo non elaborato, come si fa nel codice sopra riportato, viene visualizzato un avviso del compilatore. Non dovresti utilizzare i tipi non elaborati nel nuovo codice, ma usarli solo quando devi gestire il vecchio codice che non puoi modificare.

La combinazione di tipi non elaborati e cancellazione tipi consente di inserire tipi di oggetti in elenchi che non dovresti inserire.

Poiché il List in fase di esecuzione non sa nulla del tipo che i suoi elementi dovrebbero avere, non controlla nulla in modo da non ottenere uno ClassCastException.