Da dies eine weit verbreitete Frage ist und die aktuellen Antworten hauptsächlich erklären, warum sie nicht funktioniert (oder hackige, gefährliche Lösungen vorschlagen, die ich niemals im Produktionscode sehen würde), halte ich es für angebracht, eine weitere Antwort hinzuzufügen, die zeigt die Fallstricke und eine mögliche Lösung.
Der Grund, warum dies im Allgemeinen nicht funktioniert, wurde bereits in anderen Antworten aufgezeigt: Ob die Konvertierung tatsächlich gültig ist oder nicht, hängt von den Typen der Objekte ab, die in der ursprünglichen Liste enthalten sind. Wenn es Objekte in der Liste , dessen Typs nicht vom Typ TestB
, aber von einer anderen Unterklasse TestA
, dann ist die Besetzung nicht gültig.
Natürlich sind die Abgüsse können gültig sein. Manchmal haben Sie Informationen zu den Typen, die für den Compiler nicht verfügbar sind. In diesen Fällen ist es möglich, die Listen zu erstellen, im Allgemeinen wird jedoch nicht empfohlen :
Man könnte entweder ...
- ... die ganze Liste besetzen oder
- ... alle Elemente der Liste umwandeln
Die Implikationen des ersten Ansatzes (der der aktuell akzeptierten Antwort entspricht) sind subtil. Auf den ersten Blick scheint es richtig zu funktionieren. Wenn die Eingabeliste jedoch falsche Typen enthält ClassCastException
, wird a möglicherweise an einer völlig anderen Stelle im Code ausgegeben, und es kann schwierig sein, dies zu debuggen und herauszufinden, wo das falsche Element in die Liste aufgenommen wurde. Das schlimmste Problem ist, dass jemand möglicherweise sogar die ungültigen Elemente hinzufügt, nachdem die Liste umgewandelt wurde, was das Debuggen noch schwieriger macht.
Das Problem des Debuggens dieser Fehler ClassCastExceptions
kann mit der Collections#checkedCollection
Methodenfamilie behoben werden.
Filtern der Liste nach Typ
Eine typsicherere Methode zum Konvertieren von a List<Supertype>
nach a List<Subtype>
besteht darin , die Liste tatsächlich zu filtern und eine neue Liste zu erstellen, die nur Elemente mit einem bestimmten Typ enthält. Es gibt einige Freiheitsgrade für die Implementierung einer solchen Methode (z. B. in Bezug auf die Behandlung von null
Einträgen), aber eine mögliche Implementierung kann folgendermaßen aussehen:
/**
* 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;
}
Diese Methode kann verwendet werden, um beliebige Listen zu filtern (nicht nur mit einer bestimmten Subtyp-Supertyp-Beziehung bezüglich der Typparameter), wie in diesem Beispiel:
// 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]