Sie können jedes Objekt jederzeit in einen beliebigen Typ umwandeln, indem Sie es zuerst in Object umwandeln. in deinem Fall:
(List<Customer>)(Object)list;
Sie müssen sicher sein, dass die Liste zur Laufzeit nur Kundenobjekte enthält.
Kritiker sagen, dass ein solches Casting darauf hinweist, dass etwas mit Ihrem Code nicht stimmt. Sie sollten in der Lage sein, Ihre Typdeklarationen zu optimieren, um dies zu vermeiden. Aber Java-Generika sind zu kompliziert und nicht perfekt. Manchmal weiß man einfach nicht, ob es eine hübsche Lösung gibt, um den Compiler zufrieden zu stellen, obwohl man die Laufzeitarten sehr gut kennt und weiß, was man versucht, ist sicher. In diesem Fall führen Sie einfach das Rohabgießen nach Bedarf durch, damit Sie die Arbeit für zu Hause verlassen können.
Das braucht auch @SuppressWarnings("unchecked"). Beachten Sie, dass Sie auch zu (List)statt zu to senden können (Object).
200_erfolg
36
Das liegt daran, dass ein Kunde zwar ein Objekt ist, eine Kundenliste jedoch keine Objektliste. Wenn ja, können Sie jedes Objekt in eine Kundenliste aufnehmen.
Nein, ist es nicht. Sie würden die Typensicherheit umgehen, wenn dies zulässig wäre. Beachten Sie, dass Casting nicht bedeutet, eine neue Liste zu erstellen und über die Elemente zu kopieren. Dies bedeutet, dass die einzelne Instanz als ein anderer Typ behandelt wird und Sie daher eine Liste haben, die potenziell Nicht-Kundenobjekte mit einer Typensicherheitsgarantie enthält, die dies nicht sollte. Dies hat nichts mit Java als solchem zu tun. Da Sie der Meinung sind, dass diese Funktion Java im dunklen Zeitalter stecken lässt, fordere ich Sie auf, zu erklären, wie dies Ihrer Meinung nach funktionieren sollte.
Lasse V. Karlsen
1
@ BrainSlugs83 für Ihre Bedarfsliste (Liste <Kunde>) (Objekt);
Muthu Ganapathy Nathan
@ LasseV.Karlsen Ich spreche nicht vom Casting, ich spreche vom Konvertieren. Es würde die Typensicherheit nicht umgehen, es würde sie durchsetzen. Die Implementierung von Generika durch Java, das Fehlen von Operatorüberlastungen, Erweiterungsmethoden und vielen anderen modernen Annehmlichkeiten hat mich episch enttäuscht. - In der Zwischenzeit verfügt .NET über zwei separate Erweiterungsmethoden - eine aufgerufene .Cast<T>()und eine aufgerufene .OfType<T>(). Ersteres führt eine Umwandlung für jedes Element durch (wobei die gewünschten Ausnahmen ausgelöst werden), während letzteres Elemente herausfiltert, die nicht umgewandelt werden können (Sie würden also je nach Verwendungsszenario eines auswählen).
BrainSlugs83
1
@EAGER_STUDENT Ich würde es nicht hinter Java setzen, dass das tatsächlich funktionieren könnte (all dieses lächerliche Löschgeschäft, ich müsste es versuchen ...) - aber nein, ich würde niemals solchen Code schreiben - du verlierst Typensicherheit, was passiert, wenn ein Element in der Sammlung kein instanceofKunde ist?
BrainSlugs83
1
@ BrainSlugs83 Die Person, die die Frage speziell zum Casting gestellt hat. Und wenn Java nicht bereits über die relevanten Methoden verfügt, wie die .NET-Methoden, auf die Sie verweisen (die übrigens immer noch nicht konvertiert werden), sollten Sie sie problemlos hinzufügen können. Dies alles ist jedoch etwas orthogonal zu der vorliegenden Frage, die nach einer bestimmten Syntax fragte.
Lasse V. Karlsen
35
Abhängig von Ihrem anderen Code kann die beste Antwort variieren. Versuchen:
List<?extendsObject> list = getList();return(List<Customer>) list;
oder
List list = getList();return(List<Customer>) list;
Denken Sie jedoch daran, dass es nicht empfohlen wird, solche ungeprüften Würfe auszuführen.
-1 - Dies ist eine wirklich schlechte Angewohnheit, und wenn Sie nicht die Annotation "Unchecked" verwenden, wird sich der Compiler immer noch darüber beschweren
Beachten Sie, dass ich kein Java-Programmierer bin, aber in .NET und C # wird diese Funktion als Kontravarianz oder Kovarianz bezeichnet. Ich habe mich noch nicht mit diesen Dingen befasst, da sie neu in .NET 4.0 sind, das ich nicht verwende, da es sich nur um Beta handelt. Daher weiß ich nicht, welcher der beiden Begriffe Ihr Problem beschreibt, aber lassen Sie mich das beschreiben technisches Problem damit.
Nehmen wir an, Sie durften gießen. Beachten Sie, ich sage Besetzung , da Sie das gesagt haben, aber es gibt zwei mögliche Operationen, Besetzung und Konvertierung .
Das Konvertieren würde bedeuten, dass Sie ein neues Listenobjekt erhalten, aber Sie sagen Casting, was bedeutet, dass Sie ein Objekt vorübergehend als einen anderen Typ behandeln möchten.
Hier ist das Problem damit.
Was würde passieren, wenn Folgendes zulässig wäre (ich gehe davon aus, dass die Liste der Objekte vor der Besetzung tatsächlich nur Kundenobjekte enthält, andernfalls würde die Besetzung selbst in dieser hypothetischen Version von Java nicht funktionieren):
List<Object> list = getList();List<Customer> customers =(List<Customer>)list;
list.Insert(0,new someOtherObjectNotACustomer());Customer c = customers[0];
In diesem Fall würde dies versuchen, ein Objekt, das kein Kunde ist, als Kunden zu behandeln, und Sie würden an einem Punkt einen Laufzeitfehler erhalten, entweder in der Liste oder in der Zuweisung.
Generika sollen Ihnen jedoch typsichere Datentypen wie Sammlungen geben, und da sie das Wort "garantiert" gerne herumwerfen, ist diese Art der Besetzung mit den folgenden Problemen nicht zulässig.
In .NET 4.0 (ich weiß, Ihre Frage betraf Java) ist dies in einigen sehr speziellen Fällen zulässig , in denen der Compiler garantieren kann, dass die von Ihnen ausgeführten Vorgänge sicher sind, im Allgemeinen jedoch nicht zugelassen werden. Gleiches gilt für Java, obwohl ich mir nicht sicher bin, ob ich Pläne zur Einführung von Co- und Kontravarianz in die Java-Sprache habe.
Hoffentlich kann Ihnen jemand mit besseren Java-Kenntnissen als ich die Einzelheiten für die Java-Zukunft oder -Implementierung mitteilen.
Die Zukunft von Java ist ... Scala. Im Ernst, der Typ, der Generika auf Java verschraubt hat, hat eine neue Sprache entwickelt, die Java vage ähnlich ist, aber mit Typen wirklich, wirklich vertraut ist: Eine sehr gründliche und konsistente Implementierung der Typbehandlung. Ich denke, niemand weiß mit Sicherheit, welche Scala-Funktionen wann in Java zurückfließen werden.
Carl Smotricz
Eine ausgezeichnete Erklärung der Kovarianz, die die Frage der OP wirklich beantwortet. Gut gemacht.
Kevin Day
Carl: Ich dachte, einige Java-Entwickler haben C # erstellt? :) Wie auch immer, Java wird höchstwahrscheinlich in Zukunft in Richtung Scala gehen, anstatt beispielsweise etwas weniger stark typisiertes.
Esko
@Carl - In Scala gibt es einen subtilen Unterschied darin, dass Listen standardmäßig unveränderlich sind. So im Allgemeinen yo haben das Problem nicht ein Objekt in eine Liste der Kunden , des Hinzufügens, da , wenn Sie dies tun Sie bekommen neue Liste der Objekte .
Brian Agnew
Äh ... technisch gesehen ist dies korrekt - aber noch vor .NET 4.0 - Sie können dies mit regulären IEnumerable-Erweiterungsmethoden (.Cast <> und .OfType <>) tun - also müssen Sie nicht das tiefe Ende verlassen, wenn Sie möchten nur eine starke Typiteration.
BrainSlugs83
7
Ein anderer Ansatz wäre die Verwendung eines Java 8-Streams.
Sie können nicht, weil List<Object>und List<Customer>sind nicht im selben Vererbungsbaum.
Sie können Ihrer List<Customer>Klasse einen neuen Konstruktor hinzufügen , der a benötigt, List<Object>und dann die Liste durchlaufen, die jeweils Objectin a umgewandelt Customerund Ihrer Sammlung hinzugefügt wird. Beachten Sie, dass eine ungültige Besetzungsausnahme auftreten kann, wenn der Anrufer List<Object>etwas enthält, das keine ist Customer.
Bei generischen Listen geht es darum, sie auf bestimmte Typen zu beschränken. Sie versuchen, eine Liste zu erstellen, die alles enthalten kann (Bestellungen, Produkte usw.), und sie in eine Liste zusammenzufassen, die nur Kunden aufnehmen kann.
Wie andere bereits betont haben, können Sie sie nicht sicher wirken, da a List<Object>kein a ist List<Customer>. Sie können eine Ansicht in der Liste definieren, in der die Typprüfung direkt durchgeführt wird. Verwenden von Google-Sammlungen wäre:
returnLists.transform(list,newFunction<Object,Customer>(){publicCustomer apply(Object from){if(from instanceofCustomer){return(Customer)from;}returnnull;// or throw an exception, or do something else that makes sense.}});
Ich mag diese Lösung. Selbst wenn Sie SuppressWarnings hinzufügen müssen, ist es besser, es an einer Stelle hinzuzufügen als in jedem unsicheren Casting.
Robinson
1
Je nachdem, was Sie mit der Liste tun möchten, müssen Sie sie möglicherweise nicht einmal in eine Liste umwandeln List<Customer>. Wenn Sie Customerder Liste nur Objekte hinzufügen möchten , können Sie dies wie folgt deklarieren:
...List<Object> list = getList();return(List<?superCustomer>) list;
Dies ist legal (nicht nur legal, sondern auch korrekt) - die Liste ist von "einem Supertyp für den Kunden"), und wenn Sie sie an eine Methode übergeben, die lediglich Objekte zur Liste hinzufügt, dann die oben genannten Generische Grenzen reichen dafür aus.
Wenn Sie dagegen Objekte aus der Liste abrufen und sie stark als Kunden eingeben möchten, haben Sie zu Recht kein Glück. Da es sich bei der Liste um eine Liste handelt, List<Object>gibt es keine Garantie dafür, dass es sich bei den Inhalten um Kunden handelt. Daher müssen Sie beim Abrufen Ihr eigenes Casting bereitstellen. (Oder seien Sie wirklich, absolut, doppelt sicher, dass die Liste nur Customerseine Doppelbesetzung aus einer der anderen Antworten enthält und verwendet, aber stellen Sie fest, dass Sie die Typensicherheit zur Kompilierungszeit, die Sie von Generika erhalten, vollständig umgehen Fall).
Im Großen und Ganzen ist es immer gut, die größtmöglichen generischen Grenzen zu berücksichtigen, die beim Schreiben einer Methode akzeptabel wären, doppelt, wenn sie als Bibliotheksmethode verwendet werden soll. Wenn Sie nur aus einer Liste zu lesen , gehen, verwenden Sie List<? extends T>statt List<T>, zum Beispiel - das Ihre Anrufer gibt viel mehr Spielraum in den Argumenten sie und übermitteln können sie weniger wahrscheinlich in vermeidbare Probleme ähnlich dem laufen Sie‘ Ich bin hier.
Antworten:
Sie können jedes Objekt jederzeit in einen beliebigen Typ umwandeln, indem Sie es zuerst in Object umwandeln. in deinem Fall:
Sie müssen sicher sein, dass die Liste zur Laufzeit nur Kundenobjekte enthält.
Kritiker sagen, dass ein solches Casting darauf hinweist, dass etwas mit Ihrem Code nicht stimmt. Sie sollten in der Lage sein, Ihre Typdeklarationen zu optimieren, um dies zu vermeiden. Aber Java-Generika sind zu kompliziert und nicht perfekt. Manchmal weiß man einfach nicht, ob es eine hübsche Lösung gibt, um den Compiler zufrieden zu stellen, obwohl man die Laufzeitarten sehr gut kennt und weiß, was man versucht, ist sicher. In diesem Fall führen Sie einfach das Rohabgießen nach Bedarf durch, damit Sie die Arbeit für zu Hause verlassen können.
quelle
@SuppressWarnings("unchecked")
. Beachten Sie, dass Sie auch zu(List)
statt zu to senden können(Object)
.Das liegt daran, dass ein Kunde zwar ein Objekt ist, eine Kundenliste jedoch keine Objektliste. Wenn ja, können Sie jedes Objekt in eine Kundenliste aufnehmen.
quelle
.Cast<T>()
und eine aufgerufene.OfType<T>()
. Ersteres führt eine Umwandlung für jedes Element durch (wobei die gewünschten Ausnahmen ausgelöst werden), während letzteres Elemente herausfiltert, die nicht umgewandelt werden können (Sie würden also je nach Verwendungsszenario eines auswählen).instanceof
Kunde ist?Abhängig von Ihrem anderen Code kann die beste Antwort variieren. Versuchen:
oder
Denken Sie jedoch daran, dass es nicht empfohlen wird, solche ungeprüften Würfe auszuführen.
quelle
Mit Java 8 Streams :
Manchmal ist Brute-Force-Casting in Ordnung:
Aber hier ist eine vielseitigere Lösung:
Es gibt eine Menge Vorteile, aber einer ist, dass Sie Ihre Liste eleganter gestalten können, wenn Sie nicht sicher sind, was sie enthält:
quelle
FluentIterable
für mich gearbeitet.Sie können eine Doppelbesetzung verwenden.
quelle
Beachten Sie, dass ich kein Java-Programmierer bin, aber in .NET und C # wird diese Funktion als Kontravarianz oder Kovarianz bezeichnet. Ich habe mich noch nicht mit diesen Dingen befasst, da sie neu in .NET 4.0 sind, das ich nicht verwende, da es sich nur um Beta handelt. Daher weiß ich nicht, welcher der beiden Begriffe Ihr Problem beschreibt, aber lassen Sie mich das beschreiben technisches Problem damit.
Nehmen wir an, Sie durften gießen. Beachten Sie, ich sage Besetzung , da Sie das gesagt haben, aber es gibt zwei mögliche Operationen, Besetzung und Konvertierung .
Das Konvertieren würde bedeuten, dass Sie ein neues Listenobjekt erhalten, aber Sie sagen Casting, was bedeutet, dass Sie ein Objekt vorübergehend als einen anderen Typ behandeln möchten.
Hier ist das Problem damit.
Was würde passieren, wenn Folgendes zulässig wäre (ich gehe davon aus, dass die Liste der Objekte vor der Besetzung tatsächlich nur Kundenobjekte enthält, andernfalls würde die Besetzung selbst in dieser hypothetischen Version von Java nicht funktionieren):
In diesem Fall würde dies versuchen, ein Objekt, das kein Kunde ist, als Kunden zu behandeln, und Sie würden an einem Punkt einen Laufzeitfehler erhalten, entweder in der Liste oder in der Zuweisung.
Generika sollen Ihnen jedoch typsichere Datentypen wie Sammlungen geben, und da sie das Wort "garantiert" gerne herumwerfen, ist diese Art der Besetzung mit den folgenden Problemen nicht zulässig.
In .NET 4.0 (ich weiß, Ihre Frage betraf Java) ist dies in einigen sehr speziellen Fällen zulässig , in denen der Compiler garantieren kann, dass die von Ihnen ausgeführten Vorgänge sicher sind, im Allgemeinen jedoch nicht zugelassen werden. Gleiches gilt für Java, obwohl ich mir nicht sicher bin, ob ich Pläne zur Einführung von Co- und Kontravarianz in die Java-Sprache habe.
Hoffentlich kann Ihnen jemand mit besseren Java-Kenntnissen als ich die Einzelheiten für die Java-Zukunft oder -Implementierung mitteilen.
quelle
Ein anderer Ansatz wäre die Verwendung eines Java 8-Streams.
quelle
Sie sollten einfach die Liste durchlaufen und alle Objekte einzeln umwandeln
quelle
Sie können so etwas tun
Oder die Java 8-Methode
quelle
Sie können nicht, weil
List<Object>
undList<Customer>
sind nicht im selben Vererbungsbaum.Sie können Ihrer
List<Customer>
Klasse einen neuen Konstruktor hinzufügen , der a benötigt,List<Object>
und dann die Liste durchlaufen, die jeweilsObject
in a umgewandeltCustomer
und Ihrer Sammlung hinzugefügt wird. Beachten Sie, dass eine ungültige Besetzungsausnahme auftreten kann, wenn der AnruferList<Object>
etwas enthält, das keine istCustomer
.Bei generischen Listen geht es darum, sie auf bestimmte Typen zu beschränken. Sie versuchen, eine Liste zu erstellen, die alles enthalten kann (Bestellungen, Produkte usw.), und sie in eine Liste zusammenzufassen, die nur Kunden aufnehmen kann.
quelle
Sie können eine neue Liste erstellen und die Elemente hinzufügen:
Beispielsweise:
quelle
Am besten erstellen Sie ein neues Element
List<Customer>
, durchlaufen esList<Object>
, fügen jedes Element zur neuen Liste hinzu und geben es zurück.quelle
Wie andere bereits betont haben, können Sie sie nicht sicher wirken, da a
List<Object>
kein a istList<Customer>
. Sie können eine Ansicht in der Liste definieren, in der die Typprüfung direkt durchgeführt wird. Verwenden von Google-Sammlungen wäre:quelle
Ähnlich wie bei Bozho oben. Mit dieser Methode können Sie hier eine Problemumgehung durchführen (obwohl es mir selbst nicht gefällt):
Ja. Es wird Ihre Liste in Ihren gewünschten generischen Typ umwandeln.
Im obigen Fall können Sie folgenden Code ausführen:
quelle
Je nachdem, was Sie mit der Liste tun möchten, müssen Sie sie möglicherweise nicht einmal in eine Liste umwandeln
List<Customer>
. Wenn SieCustomer
der Liste nur Objekte hinzufügen möchten , können Sie dies wie folgt deklarieren:Dies ist legal (nicht nur legal, sondern auch korrekt) - die Liste ist von "einem Supertyp für den Kunden"), und wenn Sie sie an eine Methode übergeben, die lediglich Objekte zur Liste hinzufügt, dann die oben genannten Generische Grenzen reichen dafür aus.
Wenn Sie dagegen Objekte aus der Liste abrufen und sie stark als Kunden eingeben möchten, haben Sie zu Recht kein Glück. Da es sich bei der Liste um eine Liste handelt,
List<Object>
gibt es keine Garantie dafür, dass es sich bei den Inhalten um Kunden handelt. Daher müssen Sie beim Abrufen Ihr eigenes Casting bereitstellen. (Oder seien Sie wirklich, absolut, doppelt sicher, dass die Liste nurCustomers
eine Doppelbesetzung aus einer der anderen Antworten enthält und verwendet, aber stellen Sie fest, dass Sie die Typensicherheit zur Kompilierungszeit, die Sie von Generika erhalten, vollständig umgehen Fall).Im Großen und Ganzen ist es immer gut, die größtmöglichen generischen Grenzen zu berücksichtigen, die beim Schreiben einer Methode akzeptabel wären, doppelt, wenn sie als Bibliotheksmethode verwendet werden soll. Wenn Sie nur aus einer Liste zu lesen , gehen, verwenden Sie
List<? extends T>
stattList<T>
, zum Beispiel - das Ihre Anrufer gibt viel mehr Spielraum in den Argumenten sie und übermitteln können sie weniger wahrscheinlich in vermeidbare Probleme ähnlich dem laufen Sie‘ Ich bin hier.quelle