
Jeremy Logan
Angenommen, Sie haben zwei Klassen:
public class TestA {}
public class TestB extends TestA{}
Ich habe eine Methode, die a zurückgibt List<TestA>
und ich möchte alle Objekte in dieser Liste umwandeln TestB
so dass ich am Ende mit a List<TestB>
.

neues Konto
Einfach umwerfen List<TestB>
funktioniert fast; aber es funktioniert nicht, weil Sie einen generischen Typ eines Parameters nicht in einen anderen umwandeln können. Sie können jedoch einen zwischengeschalteten Wildcard-Typ umwandeln, und dies ist zulässig (da Sie zu und von Wildcard-Typen umwandeln können, nur mit einer ungeprüften Warnung):
List<TestB> variable = (List<TestB>)(List<?>) collectionOfListA;

Salandur
Das Casting von Generika ist nicht möglich, aber wenn Sie die Liste auf andere Weise definieren, ist es möglich, sie zu speichern TestB
drin:
List<? extends TestA> myList = new ArrayList<TestA>();
Sie müssen immer noch die Typprüfung durchführen, wenn Sie die Objekte in der Liste verwenden.

Steve Kuo
Du kannst wirklich nicht*:
Beispiel entnommen dieses Java-Tutorial
Angenommen, es gibt zwei Arten A
und B
so dass B extends A
. Dann ist folgender Code richtig:
B b = new B();
A a = b;
Der vorherige Code ist gültig, weil B
ist eine Unterklasse von A
. Was passiert nun mit List<A>
und List<B>
?
Es stellt sich heraus, dass List<B>
ist keine Unterklasse von List<A>
deshalb wir kann nicht schreiben
List<B> b = new ArrayList<>();
List<A> a = b; // error, List<B> is not of type List<A>
Außerdem wir kippen sogar schreiben
List<B> b = new ArrayList<>();
List<A> a = (List<A>)b; // error, List<B> is not of type List<A>
*: Um das Casting zu ermöglichen, brauchen wir einen gemeinsamen Elternteil für beide List<A>
und List<B>
: List<?>
zum Beispiel. Die folgende ist gültig:
List<B> b = new ArrayList<>();
List<?> t = (List<B>)b;
List<A> a = (List<A>)t;
Sie erhalten jedoch eine Warnung. Sie können es durch Hinzufügen unterdrücken @SuppressWarnings("unchecked")
zu deiner Methode.
Mit Java 8 können Sie das tatsächlich
List<TestB> variable = collectionOfListA
.stream()
.map(e -> (TestB) e)
.collect(Collectors.toList());
Ich denke jedoch, dass Sie in die falsche Richtung werfen … wenn die Methode eine Liste von zurückgibt TestA
Objekte, dann ist es wirklich nicht sicher, sie dorthin zu werfen TestB
.
Grundsätzlich bitten Sie den Compiler, Sie ausführen zu lassen TestB
Operationen auf einem Typ TestA
das unterstützt sie nicht.

Marco13
Da dies eine weit verbreitete Frage ist und die aktuellen Antworten hauptsächlich erklären, warum es nicht funktioniert (oder hackige, gefährliche Lösungen vorschlagen, die ich niemals im Produktionscode sehen möchte), halte ich es für angebracht, eine weitere Antwort hinzuzufügen die Fallstricke und eine mögliche Lösung.
Warum dies generell 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 Objekte in der Liste vorhanden sind, deren Typ nicht vom Typ ist TestB
aber von einer anderen Unterklasse von TestA
dann ist die Besetzung nicht gültig.
Natürlich die Besetzung dürfen 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 werfen, aber im Allgemeinen ist es möglich nicht empfohlen:
Man könnte entweder …
- … die ganze Liste werfen oder
- … caste alle Elemente der Liste
Die Implikationen des ersten Ansatzes (der der derzeit akzeptierten Antwort entspricht) sind subtil. Es scheint auf den ersten Blick richtig zu funktionieren. Aber wenn es falsche Typen in der Eingabeliste gibt, dann a ClassCastException
wird geworfen, vielleicht an einer ganz anderen Stelle im Code, und es kann schwierig sein, dies zu debuggen und herauszufinden, wo das falsche Element in die Liste gerutscht ist. Das schlimmste Problem ist, dass jemand sogar die ungültigen Elemente hinzufügen könnte nach dem Die Liste wurde gecastet, was das Debuggen noch schwieriger macht.
Das Problem des Debuggens dieser falschen ClassCastExceptions
kann mit gelindert werden Collections#checkedCollection
Familie von Methoden.
Filtern der Liste basierend auf dem Typ
Eine typsicherere Methode zum Konvertieren von a List<Supertype>
zu einem List<Subtype>
ist eigentlich zu Filter die Liste, und erstellen Sie eine neue Liste, die nur Elemente enthält, die einen bestimmten Typ haben. Für die Durchführung eines solchen Verfahrens gibt es einige Freiheitsgrade (z. B. hinsichtlich der Behandlung von null
Einträge), aber eine mögliche Implementierung könnte so 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]

Martinazeit
Sie können nicht werfen List<TestB>
zu List<TestA>
wie Steve Kuo erwähnt, ABER Sie können den Inhalt von ausgeben List<TestA>
hinein List<TestB>
. Versuche Folgendes:
List<TestA> result = new List<TestA>();
List<TestB> data = new List<TestB>();
result.addAll(data);
Ich habe diesen Code nicht ausprobiert, daher gibt es wahrscheinlich Fehler, aber die Idee ist, dass er das Datenobjekt durchlaufen und die Elemente (TestB-Objekte) zur Liste hinzufügen sollte. Ich hoffe, das funktioniert für Sie.
9163700cookie-checkWie wandelt man eine Liste von Supertypen in eine Liste von Subtypen um?yes