Dato che questa è una domanda ampiamente referenziata e le risposte attuali spiegano principalmente perché non funziona (o propongono soluzioni pericolose, che non vorrei mai vedere nel codice di produzione), penso che sia opportuno aggiungere un'altra risposta, mostrando le insidie e una possibile soluzione.
Il motivo per cui ciò non funziona in generale è già stato sottolineato in altre risposte: la validità effettiva della conversione dipende dai tipi di oggetti contenuti nell'elenco originale. Quando ci sono oggetti nella lista il cui tipo non è di tipo TestB
, ma di una sottoclasse diversa di TestA
, allora il cast non è valido.
Naturalmente, i cast possono essere validi. A volte hai informazioni sui tipi che non sono disponibili per il compilatore. In questi casi, è possibile eseguire il cast degli elenchi, ma in generale non è consigliabile :
Uno potrebbe o ...
- ... cast tutta la lista o
- ... cast tutti gli elementi dell'elenco
Le implicazioni del primo approccio (che corrisponde alla risposta attualmente accettata) sono sottili. A prima vista potrebbe sembrare che funzioni correttamente. Ma se ci sono tipi errati nell'elenco di input, allora ClassCastException
verrà lanciato un, forse in una posizione completamente diversa nel codice, e potrebbe essere difficile eseguire il debug di questo e scoprire dove l'elemento sbagliato è scivolato nell'elenco. Il problema peggiore è che qualcuno potrebbe persino aggiungere gli elementi non validi dopo che l'elenco è stato lanciato, rendendo ancora più difficile il debug.
Il problema del debug di questi spuri ClassCastExceptions
può essere alleviato con la Collections#checkedCollection
famiglia di metodi.
Filtro dell'elenco in base al tipo
Un modo più sicuro per la conversione da a List<Supertype>
a List<Subtype>
è in realtà filtrare l'elenco e creare un nuovo elenco che contenga solo elementi di un determinato tipo. Vi sono alcuni gradi di libertà per l'implementazione di un tale metodo (ad esempio per quanto riguarda il trattamento delle null
voci), ma una possibile implementazione può apparire così:
/**
* Filter the given list, and create a new list that only contains
* the elements that are (subtypes) of the class c
*
* @param listA The input list
* @param c The class to filter for
* @return The filtered list
*/
private static <T> List<T> filter(List<?> listA, Class<T> c)
{
List<T> listB = new ArrayList<T>();
for (Object a : listA)
{
if (c.isInstance(a))
{
listB.add(c.cast(a));
}
}
return listB;
}
Questo metodo può essere utilizzato per filtrare elenchi arbitrari (non solo con una data relazione Sottotipo-Supertipo relativa ai parametri del tipo), come in questo esempio:
// A list of type "List<Number>" that actually
// contains Integer, Double and Float values
List<Number> mixedNumbers =
new ArrayList<Number>(Arrays.asList(12, 3.4, 5.6f, 78));
// Filter the list, and create a list that contains
// only the Integer values:
List<Integer> integers = filter(mixedNumbers, Integer.class);
System.out.println(integers); // Prints [12, 78]