Was ist der Unterschied zwischen List<? super T>
y List<? extends T>
?
Ich benutzte früher List<? extends T>
aber es erlaubt mir nicht, Elemente hinzuzufügen list.add(e)
während die List<? super T>
tut.
Was ist der Unterschied zwischen List<? super T>
y List<? extends T>
?
Ich benutzte früher List<? extends T>
aber es erlaubt mir nicht, Elemente hinzuzufügen list.add(e)
während die List<? super T>
tut.
extends
Die Wildcard-Deklaration von List<? extends Number> foo3
bedeutet, dass es sich um legale Abtretungen handelt:
List<? extends Number> foo3 = new ArrayList<Number>(); // Number "extends" Number (in this context)
List<? extends Number> foo3 = new ArrayList<Integer>(); // Integer extends Number
List<? extends Number> foo3 = new ArrayList<Double>(); // Double extends Number
Lesen - Welche Art von Objekt können Sie angesichts der oben genannten möglichen Zuweisungen garantiert auslesen List foo3
:
Number
weil jede der Listen, die zugewiesen werden könnten foo3
を含む。 Number
oder eine Unterklasse von Number
.Integer
denn foo3
könnte auf eine List<Double>
.Double
denn foo3
könnte auf eine List<Integer>
.Schreiben - Welche Art von Objekt könnten Sie angesichts der oben genannten möglichen Zuordnungen zu List foo3
die legal wären für 何れも die oben genannten möglichen ArrayList
Zuweisungen:
Integer
denn foo3
könnte auf eine List<Double>
.Double
denn foo3
könnte auf eine List<Integer>
.Number
denn foo3
könnte auf eine List<Integer>
.Sie können kein Objekt zu List<? extends T>
denn man kann nicht garantieren, welche Art von List
auf den es wirklich zeigt, so dass Sie nicht garantieren können, dass das Objekt in diesem Bereich erlaubt ist. List
. Die einzige "Garantie" ist, dass Sie nur daraus lesen können und eine T
oder Unterklasse von T
.
super
Betrachten Sie nun List <? super T>
.
Die Wildcard-Deklaration von List<? super Integer> foo3
bedeutet, dass es sich um legale Abtretungen handelt:
List<? super Integer> foo3 = new ArrayList<Integer>(); // Integer is a "superclass" of Integer (in this context)
List<? super Integer> foo3 = new ArrayList<Number>(); // Number is a superclass of Integer
List<? super Integer> foo3 = new ArrayList<Object>(); // Object is a superclass of Integer
Lesen - Welche Art von Objekt erhalten Sie angesichts der oben genannten möglichen Zuordnungen garantiert, wenn Sie aus List foo3
:
Integer
denn foo3
könnte auf eine List<Number>
o List<Object>
.Number
denn foo3
könnte auf eine List<Object>
.Object
oder Unterklasse von Object
(aber Sie wissen nicht, welche Unterklasse).Schreiben - Welche Art von Objekt könnten Sie angesichts der oben genannten möglichen Zuordnungen zu List foo3
die legal wären für 何れも die oben genannten möglichen ArrayList
Zuweisungen:
Integer
weil ein Integer
ist in jeder der oben genannten Listen erlaubt.Integer
weil eine Instanz einer Unterklasse von Integer
ist in jeder der oben genannten Listen zulässig.Double
denn foo3
könnte auf eine ArrayList<Integer>
.Number
denn foo3
könnte auf eine ArrayList<Integer>
.Object
denn foo3
könnte auf eine ArrayList<Integer>
.Erinnern Sie sich an PECS : "Produzent erweitert, Konsument super" .
"Produzent verlängert" - Wenn Sie eine List
zu produzieren T
Werte (Sie wollen lesen T
s aus der Liste), müssen Sie es mit ? extends T
z.B. List<? extends Integer>
. Aber Sie können dieser Liste nichts hinzufügen.
"Consumer Super" - Wenn Sie eine List
zu konsumieren T
Werte (Sie wollen schreiben T
s in die Liste), müssen Sie sie mit ? super T
z.B. List<? super Integer>
. Es gibt jedoch keine Garantie, welche Art von Objekt Sie aus dieser Liste lesen können.
Wenn Sie sowohl von einer Liste lesen als auch in sie schreiben müssen, müssen Sie sie genau und ohne Platzhalter deklarieren, z. B. List<Integer>
.
Note dieses Beispiel aus den Java Generics FAQ . Beachten Sie, dass das Quellenverzeichnis src
(die erzeugende Liste) verwendet extends
und die Zielliste dest
(die verbrauchende Liste) verwendet super
:
public class Collections {
public static <T> void copy(List<? super T> dest, List<? extends T> src) {
for (int i = 0; i < src.size(); i++)
dest.set(i, src.get(i));
}
}
Siehe auch Wie kann ich zu List<? extends Number> Datenstrukturen hinzufügen?
Stellen Sie sich diese Hierarchie vor
Durch Schreiben
List<? extends C2> list;
Sie sagen also, dass list
in der Lage sein, auf ein Objekt des Typs (zum Beispiel) ArrayList
deren generischer Typ einer der 7 Untertypen de C2
( C2
enthalten):
new ArrayList<C2>();
, (ein Objekt, das C2 oder Subtypen speichern kann) odernew ArrayList<D1>();
(ein Objekt, das D1 oder Subtypen speichern kann) odernew ArrayList<D2>();
, (ein Objekt, das D2 oder Subtypen speichern kann) oder...und so weiter. Sieben verschiedene Fälle:
1) new ArrayList<C2>(): can store C2 D1 D2 E1 E2 E3 E4
2) new ArrayList<D1>(): can store D1 E1 E2
3) new ArrayList<D2>(): can store D2 E3 E4
4) new ArrayList<E1>(): can store E1
5) new ArrayList<E2>(): can store E2
6) new ArrayList<E3>(): can store E3
7) new ArrayList<E4>(): can store E4
Für jeden möglichen Fall gibt es einen Satz von "speicherbaren" Typen: 7 (rote) Sätze, hier grafisch dargestellt
Wie Sie sehen können, gibt es keine sichere Art die allen Fällen gemeinsam ist:
list.add(new C2(){});
denn es könnte sein list = new ArrayList<D1>();
list.add(new D1(){});
denn es könnte sein list = new ArrayList<D2>();
und so weiter.
Durch Schreiben
List<? super C2> list;
Sie sagen also, dass list
in der Lage sein, auf ein Objekt des Typs (zum Beispiel) ArrayList
deren generischer Typ einer der 7 Supertypen de C2
( C2
enthalten):
new ArrayList<A1>();
(ein Objekt, das A1 oder Subtypen speichern kann) odernew ArrayList<A2>();
(ein Objekt, das A2 oder Subtypen speichern kann) odernew ArrayList<A3>();
, (ein Objekt, das A3 oder Subtypen speichern kann) oder...und so weiter. Sieben verschiedene Fälle:
1) new ArrayList<A1>(): can store A1 B1 B2 C1 C2 D1 D2 E1 E2 E3 E4
2) new ArrayList<A2>(): can store A2 B2 C1 C2 D1 D2 E1 E2 E3 E4
3) new ArrayList<A3>(): can store A3 B3 C2 C3 D1 D2 E1 E2 E3 E4
4) new ArrayList<A4>(): can store A4 B3 B4 C2 C3 D1 D2 E1 E2 E3 E4
5) new ArrayList<B2>(): can store B2 C1 C2 D1 D2 E1 E2 E3 E4
6) new ArrayList<B3>(): can store B3 C2 C3 D1 D2 E1 E2 E3 E4
7) new ArrayList<C2>(): can store C2 D1 D2 E1 E2 E3 E4
Wir haben eine Reihe von "speicherbaren" Typen für jeden möglichen Fall: 7 (rote) Sätze, hier grafisch dargestellt
Wie Sie sehen können, haben wir hier sieben sichere Arten die allen Fällen gemeinsam sind: C2
, D1
, D2
, E1
, E2
, E3
, E4
.
list.add(new C2(){});
denn unabhängig von der Art der Liste, auf die wir uns beziehen, C2
ist erlaubtlist.add(new D1(){});
denn unabhängig von der Art der Liste, auf die wir uns beziehen, D1
ist erlaubtund so weiter. Sie haben wahrscheinlich bemerkt, dass diese Typen der Hierarchie entsprechen, die mit dem Typ C2
.
Hier die vollständige Hierarchie, wenn Sie einige Tests durchführen möchten
interface A1{}
interface A2{}
interface A3{}
interface A4{}
interface B1 extends A1{}
interface B2 extends A1,A2{}
interface B3 extends A3,A4{}
interface B4 extends A4{}
interface C1 extends B2{}
interface C2 extends B2,B3{}
interface C3 extends B3{}
interface D1 extends C1,C2{}
interface D2 extends C2{}
interface E1 extends D1{}
interface E2 extends D1{}
interface E3 extends D2{}
interface E4 extends D2{}
Ich liebe die Antwort von @Bert F., aber mein Gehirn sieht es so.
Ich habe ein X in meiner Hand. Wenn ich möchte, dass schreiben. meine X in eine Liste zu übertragen, muss diese Liste entweder eine Liste von X oder eine Liste von Dingen sein, in die meine X umgewandelt werden können, wenn ich sie eintrage, d. h. jede Oberklasse von X...
List<? super X>
Wenn ich eine Liste bekomme und ich möchte lesen ein X aus dieser Liste, dann ist das besser eine Liste von X oder eine Liste von Dingen, die zu X aufgewertet werden können, wenn ich sie vorlese, d.h. alles, was erweitert X
List<? extends X>
Ich hoffe, das hilft.
Ich würde den Unterschied gerne visualisieren. Nehmen wir an, wir haben:
class A { }
class B extends A { }
class C extends B { }
List<? extends T>
- Lesen und Zuordnen:
|-------------------------|-------------------|---------------------------------|
| wildcard | get | assign |
|-------------------------|-------------------|---------------------------------|
| List<? extends C> | A B C | List<C> |
|-------------------------|-------------------|---------------------------------|
| List<? extends B> | A B | List<B> List<C> |
|-------------------------|-------------------|---------------------------------|
| List<? extends A> | A | List<A> List<B> List<C> |
|-------------------------|-------------------|---------------------------------|
List<? super T>
- Schreiben und Zuweisen:
|-------------------------|-------------------|-------------------------------------------|
| wildcard | add | assign |
|-------------------------|-------------------|-------------------------------------------|
| List<? super C> | C | List<Object> List<A> List<B> List<C> |
|-------------------------|-------------------|-------------------------------------------|
| List<? super B> | B C | List<Object> List<A> List<B> |
|-------------------------|-------------------|-------------------------------------------|
| List<? super A> | A B C | List<Object> List<A> |
|-------------------------|-------------------|-------------------------------------------|
In allen Fällen:
können Sie jederzeit erhalten. Object
aus einer Liste unabhängig vom Platzhalter.
können Sie jederzeit hinzufügen. null
zu einer veränderbaren Liste, unabhängig vom Platzhalter.
Basierend auf Bert F's Antwort Ich möchte mein Verständnis erläutern.
Sagen wir, wir haben 3 Klassen als
public class Fruit{}
public class Melon extends Fruit{}
public class WaterMelon extends Melon{}
Hier haben wir
List<? extends Fruit> fruitExtendedList = …
//Says that I can be a list of any object as long as this object extends Fruit.
Ok, jetzt versuchen wir, einen Wert von fruitExtendedList zu erhalten
Fruit fruit = fruitExtendedList.get(position)
//This is valid as it can only return Fruit or its subclass.
Versuchen wir es noch einmal
Melon melon = fruitExtendedList.get(position)
//This is not valid because fruitExtendedList can be a list of Fruit only, it may not be
//list of Melon or WaterMelon and in java we cannot assign sub class object to
//super class object reference without explicitly casting it.
Das Gleiche gilt für
WaterMelon waterMelon = fruitExtendedList.get(position)
Versuchen wir nun, ein Objekt in fruitExtendedList zu setzen
Hinzufügen des Objekts Obst
fruitExtendedList.add(new Fruit())
//This in not valid because as we know fruitExtendedList can be a list of any
//object as long as this object extends Fruit. So what if it was the list of
//WaterMelon or Melon you cannot add Fruit to the list of WaterMelon or Melon.
Hinzufügen des Objekts Melone
fruitExtendedList.add(new Melon())
//This would be valid if fruitExtendedList was the list of Fruit but it may
//not be, as it can also be the list of WaterMelon object. So, we see an invalid
//condition already.
Schließlich versuchen wir, das WaterMelon-Objekt hinzuzufügen
fruitExtendedList.add(new WaterMelon())
//Ok, we got it now we can finally write to fruitExtendedList as WaterMelon
//can be added to the list of Fruit or Melon as any superclass reference can point
//to its subclass object.
Doch halt was wäre, wenn jemand beschließt, eine neue Art von Zitrone zu schaffen, sagen wir mal, um der Argumente willen SaltyLemon als
public class SaltyLemon extends Lemon{}
Jetzt kann fruitExtendedList eine Liste von Fruit, Melon, WaterMelon oder SaltyLemon sein.
Also, unsere Aussage
fruitExtendedList.add(new WaterMelon())
ist ebenfalls nicht gültig.
Grundsätzlich können wir sagen, dass wir nichts in eine fruitExtendedList schreiben können.
Dies fasst zusammen List<? extends Fruit>
Jetzt sehen wir
List<? super Melon> melonSuperList= …
//Says that I can be a list of anything as long as its object has super class of Melon.
Versuchen wir nun, einen Wert aus melonSuperList zu erhalten
Fruit fruit = melonSuperList.get(position)
//This is not valid as melonSuperList can be a list of Object as in java all
//the object extends from Object class. So, Object can be super class of Melon and
//melonSuperList can be a list of Object type
Ebenso kann Melon, WaterMelon oder ein anderes Objekt nicht gelesen werden.
Beachten Sie aber, dass wir Instanzen des Typs Object lesen können
Object myObject = melonSuperList.get(position)
//This is valid because Object cannot have any super class and above statement
//can return only Fruit, Melon, WaterMelon or Object they all can be referenced by
//Object type reference.
Versuchen wir nun, einen Wert aus melonSuperList zu setzen.
Hinzufügen des Objekttyps Objekt
melonSuperList.add(new Object())
//This is not valid as melonSuperList can be a list of Fruit or Melon.
//Note that Melon itself can be considered as super class of Melon.
Hinzufügen eines Objekts vom Typ Obst
melonSuperList.add(new Fruit())
//This is also not valid as melonSuperList can be list of Melon
Hinzufügen eines Objekts vom Typ Melone
melonSuperList.add(new Melon())
//This is valid because melonSuperList can be list of Object, Fruit or Melon and in
//this entire list we can add Melon type object.
Hinzufügen eines Objekts vom Typ WaterMelon
melonSuperList.add(new WaterMelon())
//This is also valid because of same reason as adding Melon
Zusammenfassend können wir Melon oder seine Unterklasse in melonSuperList hinzufügen und nur Objekte vom Typ Object lesen.
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.
39 Stimmen
Sehen Sie sich diesen ausgezeichneten Vortrag an: youtu.be/V1vQf4qyMXg?t=22m24s
1 Stimmen
Hier null können wir hinzufügen
0 Stimmen
Eine sehr gute Erklärung mit einem Beispiel @ youtube.com/watch?v=34oiEq9nD0M&feature=youtu.be&t=1630, die den <? super T> Teil erklärt, aber eine Idee von einem anderen gibt.
0 Stimmen
Nach oben hin begrenzt: docs.oracle.com/javase/tutorial/java/generics/upperBounded.html nach unten begrenzt: docs.oracle.com/javase/tutorial/java/generics/lowerBounded.html
1 Stimmen
Ich stelle mir das so vor: List<? extends B> bedeutet Liste, deren Elemente mehr als die gleichen Eigenschaften haben wie B (alle seine Unterklassen). List<? super B> bedeutet Liste, deren Elemente weniger als die gleichen Eigenschaften haben wie B (alle seine Oberklassen).