2012-03-27 12 views
6

Rispondendo a una domanda su che qui: https://stackoverflow.com/a/9872630/82609Perché possiamo usare array con riferimento generico

ho cercato di fare quanto segue:

Comparator<String>[] comparators = new Comparator[] {...}; 

Funziona! Ma quanto segue non lo fa:

Comparator<String>[] comparators = new Comparator<String>[] {...}; 

Sulla relativa domanda, ho fatto l'ipotesi:

Credo che sia perché inizialmente il contratto matrice può essere qualcosa come questo:

Se si crea un array di tipo X, non sarà MAI MAI possibile mettere in qualsiasi cosa IS-NOT-AN X. Se si t ry, si otterrà un ArrayStoreException

Permettendo così array con la creazione di farmaci generici porterebbero ad un diverso regola come:

Se si crea una matrice di tipo X<Y>, non si sarà mai mai in grado a metti qualsiasi cosa che non sia AN X. Se ci provi, riceverai un valore di ArrayStoreException . Ma puoi aggiungere entrambi gli oggetti X<Y> e X<Z> a causa della cancellazione dei tipi!


Ma a pensarci, sarebbe davvero essere un problema di avere:

Comparator<String>[] comparators = new Comparator<String>[] {...}; 

Io non capisco il motivo per cui non è possibile, dal momento che con una cosa del genere sarebbe:

  • Controllare le classi inseriti in fase di esecuzione
  • Controllare il tipo di corsi inseriti al momento della compilazione

Infine possiamo usare un array con riferimento di tipo generico e per l'impossibilità di creare un array con un tipo generico, credo che molte persone non sanno nemmeno che sia possibile.

Mi chiedo solo se qualcuno conosce il motivo di questa scelta?

E 'un po' come costringendo le persone a utilizzare List<String> = new ArrayList(); invece di utilizzare List<String> = new ArrayList<String>();


dimitrisli ti ha dato un bel exemple dal famoso libro di Joshua Bloch. Come l'ha spiegato, è pericoloso utilizzare entrambi gli array generici + covarianza e potrebbe portare a ClassCastException mentre ci si aspetta che ArrayStoreException da un array utilizzi la covarianza.

Ma vi prego di notare il seguente è ancora legale e portare alla stessa:

List<String>[] stringLists = new List[1]; 
List<Integer> intList = Arrays.asList(42); 
Object[] objects = stringLists; 
objects[0] = intList; 
String s = stringLists[0].get(0); 

tuttavia produce un avvertimento getto incontrollato in fase di compilazione, e come si menzionate, un ClassCastException in fase di esecuzione.

+0

possibile duplicato di [Errore creazione matrice generica] (http://stackoverflow.com/questions/3903196/error-generic-array-creation) –

+0

@DaveWebb cosa è duplicato? –

+0

Qualcuno ha già fatto la stessa domanda. http://stackoverflow.com/questions/3903196/error-generic-array-creation –

risposta

4

Vedo da dove vieni (e in senso pratico sono sostanzialmente d'accordo), ma penso che ci sia una differenza che motiva la situazione attuale.

Come si menziona, la cancellazione indica che i parametri generici non sono disponibili in fase di esecuzione e quindi i tipi vengono controllati in fase di compilazione (che sia per uno List<String> o Comparator<String>[]). Criticamente, questo è basato sul parametro generico della variabile .

Gli array, d'altro canto, controllano i tipi dei loro argomenti in fase di esecuzione, quando vengono inseriti, in modo che possano lanciare un ArrayStoreException se vengono utilizzati in modo improprio (in genere a causa dell'abuso della covarianza). Pertanto, gli array devono essere in grado di eseguire entrambi i controlli del punto elenco internamente e, naturalmente, non possono controllare il parametro generico in fase di runtime. Quindi non ha senso istanziare un array generico, dal momento che l'array dovrebbe ignorare completamente il parametro generico, che sarebbe fuorviante al meglio.

Detto questo, ha senso assegnare un array di questo tipo a un parametro riferimento, poiché il compilatore può eseguire controlli generici. E hai ragione nel pensare che questo copre tutte le basi e garantisce che i tipi generici siano controllati (a patto che le variabili siano parametrizzate correttamente).

La ragione alla base di questa scelta, e il motivo per cui le matrici sono diverse dalle raccolte in questo senso, è che gli array sono necessari per verificare effettivamente i tipi dei loro argomenti quando vengono inseriti, mentre le raccolte meritano la parola per e consente di immettere gli errori di tipo in un ClassCastException in seguito.

+0

Grazie, penso che l'hai fatto notare: il problema è probabilmente relativo alla covarianza dell'array –

1

Citando dal grande Effective Java Second Edition Pagina 120:

Perché creazione dell'array generico è illegale - non compila!

List<String>[] stringLists = new List<String>[1]; // (1) 
List<Integer> intList = Arrays.asList(42); // (2) 
Object[] objects = stringLists; // (3) 
objects[0] = intList; // (4) 
String s = stringLists[0].get(0); // (5) 

Facciamo finta che la linea 1, che crea una matrice generica, è legale. La riga 2 viene creata e inizializza uno List<Integer> contenente un singolo elemento. La riga 3 memorizza l'array List<String> in una variabile di matrice Oggetto, che è legale perché gli array sono covarianti. Linea 4 memorizza la List<Integer> nella suola elemento dell'array oggetto, che riesce perché i generici sono implementati di cancellatura: il tipo runtime di un'istanza List<Integer> è semplicemente List, e il tipo di runtime un'istanza List<String>[] è List[], quindi questo assegnazione non genera un ArrayStoreException. Ora siamo nei guai. Abbiamo archiviato un'istanza in una matrice dichiarata per contenere solo istanze List<String>. Nella riga 5 , recuperiamo il solo elemento dall'elenco unico di questo array. Il compilatore esegue automaticamente il cast dell'elemento recuperato su String, ma è un numero intero, quindi otteniamoa ClassCastException in fase di esecuzione.Per evitare che ciò accada, la riga 1 (che crea un array generico) genera un errore in fase di compilazione.

+0

Grazie, bel esempio, io ha modificato la mia domanda. Si noti che possiamo ancora usare List [] stringLists = new List [1]; invece e funziona bene. Sai perché è permesso? –

+1

Questo è un avviso di sicurezza del tipo perché stiamo tentando di creare utilizzando la lista delle firme crude [] e assegnarlo all'elenco generico []. Nel momento in cui lo cambiamo però nella Lista [] il compilatore si lamenta per evitare la situazione descritta. – dimitrisli

Problemi correlati