compilatori può spontaneamente eseguire la conversione, sono solo specificato di non perché le matrici generiche non possono comportarsi come matrici non generiche.
Vedi 10.5. Array Store Exception:
Per una matrice cui tipo è A[]
, dove A
è un tipo di riferimento, l'assegnazione ad un componente della matrice viene controllato in fase di esecuzione per assicurare che il valore assegnato è assegnabile al componente.
Se il tipo di valore assegnato non è compatibile con il tipo di componente, viene emesso un numero ArrayStoreException
.
Se il tipo di componente di un array non fosse reifiable, la Java Virtual Machine non poteva eseguire il controllo negozio descritto nel paragrafo precedente. Questo è il motivo per cui un'espressione di creazione di array con un tipo di elemento non-reifiable è proibita.
Un List<MyDTO>[]
non getterebbe se mettiamo qualche altro tipo di List
in esso, in modo che non si comporta come un array. Nota l'ultima frase dalla citazione: "Ecco perché è vietata un'espressione di creazione di array con un tipo di elemento non-reifiable." Questo è il motivo, è specificato che sia così. (E, per la cronaca, this reasoning has always existed, così è stato presente quando la questione è stata pubblicata nel 2011.)
Possiamo ancora fare questo:
@SuppressWarnings({"unchecked","rawtypes"})
List<MyDTO>[] dtoLists = new List[] {
new ArrayList<MyDTO>(), anExistingDtoList
};
O questo:
@SuppressWarnings("unchecked")
List<MyDTO>[] dtoLists = (List<MyDTO>[]) new List<?>[] {
new ArrayList<MyDTO>(), anExistingDtoList
};
(Oltre a controllare staticamente i tipi di argomento, la cosa varargs è equivalente: è creates a List[]
e suppresses warnings.)
Ora, certo, la specifica potrebbe essere cambiata per qualcosa di simile a "Se il tipo di valore assegnato non è compatibile con l'assegnazione con il tipo grezzo di il tipo di componente ...", ma qual è il punto? Salverebbe una manciata di personaggi in alcune situazioni insolite ma altrimenti sopprimerebbe gli avvertimenti per coloro che non capiscono le implicazioni.
Inoltre, ciò che the tutorial e altre spiegazioni tipiche che ho visto non dimostrano è quanto siano integrati gli array covarianti del sistema di tipi.
Ad esempio, data la seguente dichiarazione:
// (declaring our own because Arrays.fill is defined as
// void fill(Object[], Object)
// so the next examples would more obviously pass)
static <T> void fill(T[] arr, T elem) {
Arrays.fill(arr, elem);
}
Lo sapevate che questo compila?
// throws ArrayStoreException
fill(new String[1], new Integer(0));
E questo compila anche:
// doesn't throw ArrayStoreException
fill(dtoLists, new ArrayList<Float>());
Prima di Java 8, potremmo fare quelle chiamate a fill
fallire dandogli la seguente dichiarazione:
static <T, U extends T> void fill(T[] arr, U elem) {...}
Ma questo era solo un problema con l'inferenza di tipo, e ora funziona "correttamente", mettendo ciecamente List<Float>
in un List<MyDTO>[]
.
Questo si chiama inquinamento mucchio. Può causare il lancio di un numero ClassCastException
in un secondo momento, probabilmente da qualche parte completamente estraneo alle azioni che hanno effettivamente causato il problema. L'inquinamento di heap con un contenitore generico come List
richiede azioni meno sicure, come l'uso di raw types, ma qui, possiamo causare implicitamente l'inquinamento dell'heap e senza alcun avviso.
Gli array generici (e in realtà gli array in generale) ci forniscono solo il controllo statico nelle circostanze più semplici.
Quindi è evidente che i progettisti di linguaggi hanno pensato che fosse meglio non autorizzarli, ei programmatori che capiscono i problemi che presentano possono sopprimere gli avvertimenti e bypassare la restrizione.
possibile duplicato di [Array of Generic List] (http://stackoverflow.com/questions/7810074/array-of-generic-list) – Thilo
controllare la risposta più alta su quel duplicato. Ha un esempio perché questo non è permesso. – Thilo
Non è un duplicato. La mia domanda richiede risposte sui problemi di progettazione del compilatore. –