Ich habe eine Liste, die wie folgt deklariert ist:
List<? extends Number> foo3 = new ArrayList<Integer>();
Ich habe versucht, foo3 3 hinzuzufügen. Ich erhalte jedoch eine Fehlermeldung wie folgt:
The method add(capture#1-of ? extends Number) in the type List<capture#1-of ?
extends Number> is not applicable for the arguments (ExtendsNumber)
List<? extends Number>
dies nicht "Liste von Objekten unterschiedlichen Typs, die sich alle erstreckenNumber
" bedeutet. Es bedeutet "Liste von Objekten eines einzelnen Typs, die sich erweiternNumber
".Antworten:
Entschuldigung, aber du kannst nicht.
Die Platzhalterdeklaration von
List<? extends Number> foo3
bedeutet, dass die Variablefoo3
einen beliebigen Wert aus einer Typenfamilie enthalten kann (anstelle eines beliebigen Werts eines bestimmten Typs). Dies bedeutet, dass es sich bei diesen um rechtliche Aufträge handelt:List foo3
Vor diesem Hintergrund wäre es nach einer der oben genannten möglichenArrayList
Zuweisungen legal , welche Art von Objekt Sie hinzufügen könnten :Integer
dafoo3
dies auf eine zeigen könnteList<Double>
.Double
dafoo3
dies auf ein zeigen könnteList<Integer>
.Number
weil hinzufügenfoo3
dies auf ein zeigen könnteList<Integer>
.Sie können kein Objekt hinzufügen,
List<? extends T>
da Sie nicht garantieren können, auf welche Art von ObjektList
es wirklich zeigt. Sie können also nicht garantieren, dass das Objekt darin zulässig istList
. Die einzige "Garantie" ist, dass Sie nur daraus lesen können und eineT
oder eine Unterklasse von erhaltenT
.Die umgekehrte Logik gilt
super
zList<? super T>
. Diese sind legal:Sie können den spezifischen Typ T (z. B.
Number
) nicht lesen,List<? super T>
da Sie nicht garantieren können, auf welche Art von Typ TList
wirklich zeigt. Die einzige "Garantie", die Sie haben, ist, dass Sie einen Wert vom Typ hinzufügen könnenT
(oder eine Unterklasse vonT
) ohne die Integrität der Liste zu verletzen, auf die verwiesen wird.Das perfekte Beispiel dafür ist die Signatur für
Collections.copy()
:Beachten Sie, wie die
src
Listendeklarationextends
es mir ermöglicht, eine Liste aus einer Familie verwandter Listentypen zu übergeben und dennoch zu gewährleisten, dass Werte vom Typ T oder Unterklassen von T erzeugt werden. Sie können dersrc
Liste jedoch keine Werte hinzufügen .Das
dest
Listendeklarationsuper
ermöglicht es mir, eine Liste aus einer Familie verwandter Listentypen zu übergeben und trotzdem zu garantieren, dass ich einen Wert eines bestimmten Typs T in diese Liste schreiben kann. Es kann jedoch nicht garantiert werden, dass die Werte des bestimmten Typs T gelesen werden, wenn ich aus der Liste lese.Dank generischer Platzhalter kann ich jetzt jeden dieser Aufrufe mit dieser einzigen Methode ausführen:
Betrachten Sie diesen verwirrenden und sehr breiten Code, um Ihr Gehirn zu trainieren. Die auskommentierten Zeilen sind illegal und der Grund dafür ist ganz rechts in der Zeile angegeben (Sie müssen scrollen, um einige davon zu sehen):
quelle
src
List
Argument wirdextends
zum Lesen aus der src-Liste verwendet, während dasdest
List
Argumentsuper
zum Schreiben in die Zielliste verwendet wird. Dies ermöglicht eine Methode, die vonList<Integer>
oderList<Double>
inList<Number>
oder kopieren kannList<Object>
.or subclass of T
ist richtig. Zum Beispiel kann ich kein anObject
(Superklasse vonNumber
) hinzufügen ,List<? super Number> foo3
dafoo3
möglicherweise Folgendes zugewiesen wurde:List<? super Number> foo3 = new ArrayList<Number>
(das nurNumber
oder Unterklassen von enthalten kannNumber
).<? super Number>
bezieht sich auf die Arten vonList<>
s, die zugewiesen werden könnenfoo3
- nicht auf die Arten von Dingen, die hinzugefügt / daraus gelesen werden können. Die Arten von Dingen, die hinzugefügt / entferntfoo3
werden können, müssen Dinge sein, die zu jeder Art von Dingen hinzugefügt / entfernt werdenList<>
können, denen zugewiesen werden kannfoo3
.Sie können nicht (ohne unsichere Würfe). Sie können nur von ihnen lesen.
Das Problem ist, dass Sie nicht genau wissen, von welcher Liste die Liste ist. Es kann sich um eine Liste einer beliebigen Unterklasse von Number handeln. Wenn Sie also versuchen, ein Element darin einzufügen, wissen Sie nicht, dass das Element tatsächlich in die Liste passt.
Zum Beispiel könnte die Liste eine Liste von
Byte
s sein, also wäre es ein Fehler, einFloat
in sie zu setzen .quelle
"List '<'? Extend Number> ist eigentlich ein Platzhalter für die obere Schranke!
Der Platzhalter mit der oberen Grenze besagt, dass jede Klasse, die Number oder Number selbst erweitert, als formaler Parametertyp verwendet werden kann: Das Problem ergibt sich aus der Tatsache, dass Java nicht weiß, welcher Typ List wirklich ist. Es muss ein GENAUER und EINZIGARTIGER Typ sein. Ich hoffe, es hilft :)
quelle
Sie könnten dies stattdessen tun:
quelle
Es war verwirrend für mich, obwohl ich hier Antworten gelesen habe, bis ich den Kommentar von Pavel Minaev fand:
Danach konnte ich BertF tolle Erklärung verstehen. Liste <? erweitert Anzahl> bedeutet? Es kann sich um einen beliebigen Typ handeln, der Number erweitert (Integer, Double usw.) und in der Deklaration (List <? erweitert Number> list) nicht klarstellt , um welche von ihnen es sich handelt. Wenn Sie also die add-Methode verwenden möchten, ist nicht bekannt, ob die Eingabe erfolgt vom gleichen Typ oder nicht; Was ist der Typ überhaupt?
Also die Elemente von List <? erweitert Nummer> konnte nur beim Konstruieren gesetzt werden.
Beachten Sie auch Folgendes: Wenn wir Vorlagen verwenden, teilen wir dem Compiler mit, mit welchem Typ wir herumspielen. T zum Beispiel hält diesen Typ für uns, aber nicht ? macht das gleiche
Ich muss sagen .. Dies ist einer der schmutzigen zu erklären / lernen
quelle
Wenn Sie die Liste von 'Objekt' erweitern, können Sie list.add verwenden, und wenn Sie list.get verwenden möchten, müssen Sie nur das Objekt in Ihr Objekt umwandeln.
quelle