Ich habe diese Themen durchgearbeitet
Ich scheine jedoch immer noch irgendwie mit dem super
Schlüsselwort verloren zu sein :
Wenn wir eine solche Sammlung deklarieren:
List<? super Number> list = null; list.add(new Integer(0)); // this compiles list.add(new Object()); // this doesn't compile
sollte es nicht das Gegenteil sein - wir haben eine Liste, die einige Objekte (unbekannten Typs) enthält, deren Eltern Eltern sind Number
. Also Object
sollte passen (da es das Elternteil von ist Number
) und Integer
sollte nicht. Das Gegenteil ist aus irgendeinem Grund der Fall.
Vorausgesetzt, wir haben den folgenden Code
static void test(List<? super Number> param) { param.add(new Integer(2)); } public static void main(String[] args) { List<String> sList = new ArrayList<String>(); test(sList); // will never compile, however... }
Es ist unmöglich, den obigen Code zu kompilieren (und meine Vernunft legt nahe, dass dies das richtige Verhalten ist), aber die grundlegende Logik könnte das Gegenteil beweisen:
String is Object, Object is superclass of Number. So String should work.
Ich weiß, das ist verrückt, aber ist das nicht der Grund, warum sie keine <S super T>
Konstrukte zugelassen haben? Wenn ja, warum <? super T>
ist das dann erlaubt?
Könnte mir jemand helfen, den fehlenden Teil dieser Logikkette wiederherzustellen?
Der erste Teil
List<Number>
passt hinein,List<? super Number>
aber Sie können keinObject
zu einem hinzufügenList<Number>
. Aus diesem Grund kann man nicht hinzufügenObject
zuList<? super Number>
.Auf der anderen Seite können Sie jede Unterklasse von
Number
(Number
enthalten) zu Ihrer Liste hinzufügen .Für den zweiten Teil
String
ist eineObject
, aberString
keine Oberklasse vonNumber
.Wenn es so funktionieren würde, da jede Klasse eine Unterklasse von ist
Object
,super
hätte es keine Bedeutung.Sehen wir uns alle möglichen Fälle an mit
List<? super Number>
:List<Object>
List<Object>
wird funktionierenObject
passt<? super Number>
Number
zu hinzufügenList<Object>
String
Sie sich nur sicher, dass Sie eine beliebige Unterklasse von hinzufügen könnenNumber
.List<Number>
:List<Number>
wird funktionierenNumber
passt<? super Number>
Number
zu hinzufügenList<Number>
List<Integer>
(oder eine beliebige Unterklasse vonNumber
):List<Integer>
wird nicht funktionierenNumber
also ist es genau das, was wir vermeiden wollenInteger
in ein passt, könnenNumber
Sie keine Unterklasse vonNumber
inList<Integer>
(zum Beispiel aFloat
) hinzufügen.super
bedeutet nicht eine Unterklasse.List<String>
(oder eine Klasse, die sich weder erweitertNumber
noch in der "Superhierarchie" vonNumber
(dhNumber
undObject
) befindet:List<String>
wird nicht funktionierenString
passt nicht inNumber
"Superhierarchie"String
passt inObject
(die eine SuperklasseNumber
) Sie woudln't sicher ein hinzufügen zu können , werdenNumber
auf eine ,List
die jede Unterklasse von einer der Superklassen enthaltenNumber
)super
bedeutet nicht, dass eine Unterklasse einer der Superklassen vorliegt, sondern nur eine der Superklassen.Wie funktioniert es ?
Sie können sagen, dass das Schlüsselwort respektiert wird , solange Sie eine Unterklasse von
Number
mit Ihrer Eingabe hinzufügen können .List
super
quelle
Ich habe es eine Weile nicht verstanden. Viele der Antworten hier und die anderen Fragen zeigen speziell, wann und wo bestimmte Verwendungen Fehler sind, aber nicht so sehr warum.
So habe ich es endlich verstanden. Wenn ich eine Funktion habe, die
Number
s zu a hinzufügtList
, möchte ich sie möglicherweise vom Typ hinzufügen, derMySuperEfficientNumber
meine eigene benutzerdefinierte Klasse ist, die implementiertNumber
(aber keine Unterklasse vonInteger
). Jetzt weiß der Anrufer vielleicht nichts darüberMySuperEfficientNumber
, aber solange er weiß, dass er die zur Liste hinzugefügten Elemente als nichts Spezifischeres behandeltNumber
, ist alles in Ordnung.Wenn ich meine Methode wie folgt deklariert habe:
public static void addNumbersToList(List<? extends Number> numbers)
Dann könnte der Anrufer eine übergeben
List<Integer>
. Wenn meine Methode a hinzugefügtMySuperEfficientNumber
zu Endenumbers
, dann würde der Anrufer nicht mehr über einenList
vonInteger
s und der folgenden Code nicht funktionieren würde:List<Integer> numbers = new ArrayList<Integer>(); addNumbersToList(numbers); // The following would return a MySuperEfficientNumber not an Integer Integer i = numbers.get(numbers.size()-1)
Offensichtlich kann das nicht funktionieren. Und der Fehler würde innerhalb der
addNumbersToList
Methode liegen. Sie würden so etwas bekommen wie:The method add... is not applicable for the arguments (MySuperEfficientNumber)
Denn es
numbers
könnte sich um eine bestimmte Art handelnNumber
, die nicht unbedingtMySuperEfficientNumber
kompatibel ist. Wenn ich die Deklaration umdrehensuper
würde, würde die Methode ohne Fehler kompiliert, aber der Code des Aufrufers würde fehlschlagen mit:The method addNumbersToList(List<? super Number>)... is not applicable for the arguments (List<Integer>)
Weil meine Methode sagt: "Glaube nicht, dass du
List
etwas Spezifischeres sein kannst alsNumber
. Ich könnteNumber
der Liste alle möglichen seltsamen Dinge hinzufügen , du musst dich nur darum kümmern. Wenn du an sie denken willst als etwas noch allgemeineres alsNumber
- wieObject
- das ist in Ordnung, ich garantiere, dass sie mindestensNumber
s sein werden, aber Sie können sie allgemeiner behandeln, wenn Sie wollen. "Während
extends
sagt: "Es ist mir egal, welche Art vonList
Ihnen mir geben, solange jedes Element mindestens ein istNumber
. Es kann jede Art vonNumber
, sogar Ihre eigenen seltsamen, benutzerdefinierten,Number
erfundenen sein. Solange Sie implementieren diese Schnittstelle, wir sind gut. Ich werde Ihrer Liste nichts hinzufügen, da ich nicht weiß, welchen konkreten Typ Sie dort tatsächlich verwenden. "quelle
List<? super Number>
bedeutet, dass der Referenztyp der Variablen darauf hindeutet, dass wir eine Liste von Zahlen, Objekten oder Serializables haben.Der Grund, warum Sie kein Objekt hinzufügen können, liegt darin, dass der Compiler nicht weiß, WELCHE dieser Klassen in der generischen Definition des tatsächlich instanziierten Objekts enthalten sind. Daher können Sie nur Number oder Subtypen von Number wie Double, Integer und übergeben demnächst.
Angenommen, wir haben eine Methode, die a zurückgibt
List<? super Number>
. Die Erstellung des Objekts innerhalb der Methode ist aus unserer Sicht gekapselt. Wir können nur nicht sagen, ob es so etwas ist:List<? super Number> returnValue = new LinkedList<Object>();
oder
List<? super Number> returnValue = new ArrayList<Number>();
Der generische Typ könnte also Objekt oder Nummer sein. In beiden Fällen dürfen wir Number hinzufügen, aber nur in einem Fall dürfen wir Object hinzufügen.
In dieser Situation müssen Sie zwischen dem Referenztyp und dem tatsächlichen Objekttyp unterscheiden.
quelle
List<? super Number>
ist so ein Ort, anList<AncestorOfNumber>
dem wir implizit jedenNumber
auf seinen Supertyp umwandeln könnenAncestorOfNumber
.Beachten Sie
????
Folgendes : Welcher generische Typ muss im folgenden Beispiel vorhanden sein?InputStream mystream = ...; void addTo(List<????> lsb) { lsb.add(new BufferedInputStream(mystream)); } List<BufferedInputStream> lb = new ArrayList<>(); List<InputStream> li = new ArrayList<>(); List<Object> lo = new ArrayList<>(); ... { addTo(lb); addTo(li); addTo(lo); }
Die Antwort:
????
ist alles, worauf wir werfen könnenBufferedInputStream
, was genau dasselbe oder einer seiner Vorfahren ist:? super BufferedInputStream
quelle
Darf ich ein sehr einfaches Beispiel geben?
public void add(List<? super Number> list) { }
Dies ermöglicht diese Anrufe
add(new LinkedList<Number>());
und alles über Nummer wie
add(new LinkedList<Object>());
aber nichts unterhalb der Hierarchie also nicht
add(new LinkedList<Double>());
oder
add(new LinkedList<Integer>());
Da es für das Programm nicht klar ist, ob Sie eine Liste mit Nummer oder Objekt angeben, kann der Compiler nicht zulassen, dass Sie etwas über Nummer hinzufügen.
Zum Beispiel würde eine Liste kein Objekt akzeptieren, obwohl ein Objekt eine Nummer akzeptieren würde. Da dies jedoch nicht klar ist, wäre die einzige gültige Eingabe die Zahl und ihre Untertypen.
quelle
Es gibt zwei Winkel hier: was Sie setzen in eine Sammlung und was Sie bekommen aus einer Sammlung, wenn begrenzt Typen beteiligt sind.
Schauen wir uns zuerst den
? extends Number
Fall an. Wenn eine Sammlung mit solchen Grenzen definiert ist, wissen wir Folgendes: Jedes Element hat eine Obergrenze alsNumber
. Wir kennen den genauen Typ nicht (könnte ein seinInteger/Long/etc
), aber wir wissen sicher, dass seine Obergrenze istNumber
.Das Lesen aus einer solchen Sammlung bringt uns also eine
Number
. Dies ist der einzige garantierte Typ, den wir daraus erhalten können.Das Schreiben in eine solche Sammlung ist verboten. Aber wieso? Habe ich das nicht gesagt, während wir lesen - wir werden immer eine bekommen
Number
, warum also das Schreiben verbieten? Die Situation ist hier etwas komplizierter:List<Integer> ints = ....; List<? extends Number> numbers = ints; numbers.add(12D); // add a double in here
Wenn das Hinzufügen erlaubt gewesen wäre, hätten
numbers
Sie effektiv einDouble
in a hinzufügen könnenList of Integers
.Nun zu Ihrem Beispiel:
List<? super Number> list = null; list.add(new Integer(0)); list.add(new Object());
Wir wissen,
list
dass es zum Beispiel einen bestimmten Supertyp von enthält .Number
Object
Das Lesen von einer solchen Liste würde uns einen bestimmten Typ geben
X
, von demX
ein Elternteil wäreNumber
. Was wäre das? Du kannst es nicht wirklich wissen. Es könnte theoretischMyNumber extends Number
oder viel einfacher sein: anObject
. Da Sie nicht sicher wissen können, wäre die einzige sichere Sache, aus der Sie lesen können, der Supertyp von allem -Object
.Was ein bisschen komisch ist, kann sein:
List<? super String> list = ...; String s = list.get(0); // fails, compiler does not care that String is final
Das Schreiben ist etwas komplizierter, aber nur geringfügig. Denken Sie daran, was wir wissen
list
: Es ist ein Typ, derNumber
erweitert / implementiert wird (wenn es eine Schnittstelle wäre), sodass Sie diesem Supertyp immer einen Subtyp (oder sichNumber
selbst) zuweisen können .quelle