2015-05-27 20 views
6
public void run(){ 
    setFont("Courier-24"); 
    //Define list as ArrayList<Integer> 
    ArrayList<Integer> list = new ArrayList<Integer>(); 
    readList(list); 
} 

private void readList(ArrayList list){ 
    list.add("Hello"); 
    list.add(2); 
    println("list = "+list); 
    println("Type of list = "+list.get(0).getClass()); 
    println("Type of list = "+list.get(1).getClass()); 
} 

Risultato:ArrayList <Integer> cambia automaticamente il tipo di ArrayList <String>

list = [Ciao, 2]
Tipo di list = classe java.lang.String
Tipo di list = classe Java .lang.Integer

Ecco il mio codice e il risultato. La mia domanda è, come è possibile che ArrayList di tipo Integer possa memorizzare oggetti String? Qual è il tipo di lista ora? E che meccanismo è questo?

+0

"Java", non "JAVA". – ace

+2

1. Stai usando il tipo 'Raw' in' readList() '. 2. Leggi di "cancellazione dei tipi". –

+0

Stai ** non ** recuperando un tipo di 'Lista'. Stai recuperando il tipo del ** primo elemento ** di 'List'. –

risposta

6

I generici di Java in realtà non cambiano la classe o l'oggetto sottostante, forniscono solo semantica di compilazione (principalmente) attorno ad essi.

viene trasmesso un ArrayList<Integer> in un metodo in attesa di un ArrayList (che può contenere qualsiasi cosa ), si sta bypassando la capacità del compilatore di fornire con la sicurezza che tipo.

Il Java Generics Tutorial spiega questo, e perché Java implementa generici in questo modo. This page, in particolare, si concentra su di esso:

Generics sono state introdotte per il linguaggio Java per fornire controlli di tipo più stretti al momento della compilazione e per supportare la programmazione generica. Per implementare i generici, il compilatore Java applica la cancellazione di tipo a:

  • Sostituisci tutti i parametri di tipo in tipi generici con i relativi limiti o Oggetto se i parametri di tipo sono illimitati. Il codice prodotto, quindi, contiene solo classi, interfacce e metodi ordinari.
  • Inserire tipi di cast, se necessario, per preservare la sicurezza del tipo.
  • Generare metodi bridge per preservare il polimorfismo in tipi generici estesi.

La cancellazione del tipo garantisce che non vengano create nuove classi per tipi parametrizzati; di conseguenza, i generici non comportano nessun sovraccarico di runtime.

Quello che non dice è che questo permette anche il codice scritto con farmaci generici (come il vostro run) di interagire con il codice scritto senza farmaci generici (come il vostro readList), che è importante quando si aggiunge una caratteristica a una lingua ben consolidata con un'enorme base di libreria (come lo erano quando si aggiungevano i generici a Java).

+0

Grazie! Qui ho qualche idea dopo aver letto. Quando chiamo 'readList (list)', in realtà aggiunge cose nella lista che sono 'falsamente' considerate come tipo 'ArrayList' quindi non ci sono errori. Ma se chiamo 'println (" Type of list = "+ list.get (0) .getClass());' in 'run()' viene l'errore. È come un criminale fuggito dalla scena del crimine in un primo momento (perché appartiene alle persone normali e la gente normale ha libertà), e quando la polizia inizia a controllare tutti quelli che lo circondano viene catturato perché è un criminale in profondità? – kahofanfan

+0

@kahofanfan: È perché in 'run', il compilatore sta automaticamente aggiungendo automaticamente il casting per te. Quindi in 'run', dove si ha un' ArrayList ',' list.get (0) 'diventa effettivamente' (Integer) list.get (0) '. Quindi, se c'è un non 'Intero' nell'elenco, poiché quando si aggiunge la stringa si utilizza un riferimento non parametrizzato all'elenco, si ottiene un errore di runtime dal cast. –

1

Nel parametro readList del metodo non è stato limitato a solo i tipi di valore Integer, pertanto list non ottiene i vantaggi del controllo in fase di compilazione e deve fare ricorso al controllo del tipo di runtime.

+0

E dove vedi un risultato del "controllo del tipo di runtime" in questa domanda? O succede davvero? – Tom

+0

E a causa della cancellazione del tipo non è possibile eseguire il controllo del tipo di runtime in modo che alla fine si manifesti generando un'eccezione. –

+0

@Tom questa domanda non mostra il controllo del tipo di runtime - ma è lì. @ PM77-1 'type erasure' rimuove il controllo in fase di compilazione non il controllo in fase di esecuzione. Ad esempio, se provi a trasmettere i valori a int, ottieni un'eccezione in fase di esecuzione per il valore String. L'eccezione che hai menzionato è la verifica del tipo di runtime IS. – neuronaut

1

Dichiarazione

ArrayList list 

nel metodo readList equivalente alla

ArrayList<Object> list 

È ovvio che String è oggetto, così come numero intero. Quando si passa a println, entrambi saranno sincronizzati con i propri metodi.

+0

La mia digitazione mi delude :) – basme

3

Quando si dichiara:

private void readList(ArrayList list) 

non si specifica alcun tipo a questo ArrayList modo per impostazione predefinita è di tipo Object.

Entrambe String e Integer (infatti tutte le classi in java) sono sottotipi di Object. Quindi è possibile aggiungerli alla lista.

Per ulteriori informazioni sui generici senza tipi, leggere here. In breve, i tipi generici sono solo per i controlli del tempo di compilazione, in modo da non aggiungere tipi errati (che possono in seguito causare eccezioni.) In questo caso le operazioni su String e Integer sono compatibili per fortuna senza errori).

1

Penso che il tipo ArrayList senza le specifiche generiche passate come argomento sia assument come ArrayList. Sia String che Integer ereditano l'oggetto in modo che entrambi possano essere aggiunti nell'elenco. Tuttavia gli elementi ArrayList sono di tipo Objects.