Was ist der Unterschied zwischen List<? super T>
und List<? extends T>
?
Ich habe List<? extends T>
verwendet, aber ich kann nicht list.add(e)
Elemente hinzufügen, während List<? super T>
dies tut.
extends
Die Wildcard-Deklaration von List<? extends Number> foo3
bedeutet, dass es sich hierbei um rechtliche Aufträge 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
Reading - Unter Berücksichtigung der oben genannten möglichen Zuordnungen, welchen Objekttyp Sie garantiert aus List foo3
lesen können:
Number
lesen, da jede der Listen, die foo3
zugewiesen werden könnten, eine Number
oder eine Unterklasse von Number
enthält.Integer
nicht lesen, da foo3
auf einen List<Double>
zeigen könnte.Double
nicht lesen, da foo3
auf einen List<Integer>
zeigen könnte.Writing - Welchen Objekttyp könnten Sie angesichts der oben genannten möglichen Zuweisungen zu List foo3
hinzufügen, der für all die oben möglichen möglichen ArrayList
-Zuweisungen zulässig wäre:
Integer
hinzufügen, da foo3
auf einen List<Double>
zeigen könnte.Double
hinzufügen, da foo3
auf einen List<Integer>
zeigen könnte.Number
hinzufügen, da foo3
auf einen List<Integer>
zeigen könnte.Sie können kein Objekt zu List<? extends T>
hinzufügen, da Sie nicht garantieren können, auf welche Art von List
es wirklich verweist. Sie können also nicht garantieren, dass das Objekt in List
zulässig ist Sie können nur davon lesen und erhalten eine T
oder eine Unterklasse von T
.
super
Betrachten Sie nun List <? super T>
.
Die Wildcard-Deklaration von List<? super Integer> foo3
bedeutet, dass es sich hierbei um rechtliche Aufträge 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
Reading - Welche Art von Objekt erhalten Sie aufgrund der oben genannten möglichen Zuweisungen garantiert, wenn Sie von List foo3
lesen:
Integer
ist nicht garantiert, da foo3
auf List<Number>
oder List<Object>
zeigen könnte.Number
ist nicht garantiert, da foo3
auf einen List<Object>
zeigen könnte.Object
oder einer Unterklasse von Object
erhalten (Sie wissen jedoch nicht, welche Unterklasse).Writing - Welchen Objekttyp könnten Sie angesichts der oben genannten möglichen Zuweisungen zu List foo3
hinzufügen, der für all die oben möglichen möglichen ArrayList
-Zuweisungen zulässig wäre:
Integer
hinzufügen, da in einer der obigen Listen eine Integer
zulässig ist.Integer
hinzufügen, da eine Instanz einer Unterklasse von Integer
in einer der obigen Listen zulässig ist.Double
hinzufügen, da foo3
auf einen ArrayList<Integer>
zeigen könnte.Number
hinzufügen, da foo3
auf einen ArrayList<Integer>
zeigen könnte.Object
hinzufügen, da foo3
auf einen ArrayList<Integer>
zeigen könnte.Denken Sie an PECS: "Producer erweitert, Consumer Super".
"Producer Extends" - Wenn Sie eine List
benötigen, um T
-Werte zu erzeugen (Sie möchten T
s aus der Liste lesen), müssen Sie sie mit ? extends T
deklarieren, z. List<? extends Integer>
. Sie können diese Liste jedoch nicht hinzufügen.
"Consumer Super" - Wenn Sie eine List
benötigen, um T
-Werte zu verwenden (Sie möchten T
s in die Liste schreiben), müssen Sie sie mit ? super T
deklarieren, z. List<? super Integer>
. Es gibt jedoch keine Garantie dafür, welche Art von Objekten Sie aus dieser Liste lesen können.
Wenn Sie aus einer Liste sowohl lesen als auch schreiben müssen, müssen Sie sie ohne Wildcards genau angeben, z. List<Integer>
.
Hinweis dieses Beispiel aus den Java Generics FAQ . Beachten Sie, wie die Quellliste src
(die erzeugende Liste) extends
verwendet und die Zielliste dest
(die konsumierende Liste) 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 zur Liste hinzugefügt werden? Anzahl> Datenstrukturen erweitert?
Stellen Sie sich vor, Sie hätten diese Hierarchie
Durch schreiben
List<? extends C2> list;
sie sagen, dass list
auf ein Objekt des Typs verweisen kann (zum Beispiel) ArrayList
, dessen generischer Typ einer der 7 subtypes von C2
ist (C2
enthalten):
new ArrayList<C2>();
(ein Objekt, das C2 oder Untertypen speichern kann) odernew ArrayList<D1>();
(ein Objekt, das D1 oder Untertypen speichern kann) odernew ArrayList<D2>();
(ein Objekt, das D2 oder Untertypen 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 "speicherbarer" Typen: 7 (rote) Sätze werden hier grafisch dargestellt
Wie Sie sehen, gibt es kein sicherer Typ, das in jedem Fall gleich ist:
list.add(new C2(){});
, da es list = new ArrayList<D1>();
sein könntelist.add(new D1(){});
, da es list = new ArrayList<D2>();
sein könnteund so weiter.
Durch schreiben
List<? super C2> list;
sie sagen, dass list
auf ein Objekt des Typs verweisen kann (zum Beispiel) ArrayList
, dessen generischer Typ einer der 7 supertypes von C2
(C2
enthalten) ist:
new ArrayList<A1>();
(ein Objekt, das A1 oder Untertypen speichern kann) odernew ArrayList<A2>();
(ein Objekt, das A2 oder Untertypen speichern kann) odernew ArrayList<A3>();
(ein Objekt, das A3 oder Untertypen 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
Für jeden möglichen Fall gibt es einen Satz "speicherbarer" Typen: 7 (rote) Sätze werden hier grafisch dargestellt
Wie Sie sehen, haben wir hier sieben sichere Typen, die in jedem Fall gleich sind: C2
, D1
, D2
, E1
, E2
, E3
, E4
.
list.add(new C2(){});
verwenden, da C2
unabhängig von der Art der Liste, auf die wir uns beziehen, zulässig istlist.add(new D1(){});
verwenden, da D1
unabhängig von der Art der Liste, auf die wir uns beziehen, zulässig istund so weiter. Sie haben wahrscheinlich bemerkt, dass diese Typen der Hierarchie entsprechen, beginnend 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 so sieht es mein Gehirn.
Ich habe ein X in der Hand. Wenn ich mein X in eine Liste schreiben möchte , muss diese Liste entweder eine Liste von X oder eine Liste von Dingen sein, die mein X auf den Kopf stellen kann zu wie ich sie schreibe zB in irgendeiner Oberklasse von X ...
List<? super X>
Wenn ich eine Liste bekomme und ich möchte ein X aus dieser Liste lesen , dann ist das besser eine Liste von X oder eine Liste von Dingen, die es sein können upcast to X wie ich sie vorlese, dh alles, was X erweitert
List<? extends X>
Hoffe das hilft.
Basierend auf Antwort von Bert F möchte ich mein Verständnis erläutern.
Nehmen wir an, 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 wollen wir versuchen, einen Wert aus 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.
Gleiches gilt für
WaterMelon waterMelon = fruitExtendedList.get(position)
Versuchen wir nun, ein Objekt in fruitExtendedList zu setzen
Fruchtgegenstand hinzufügen
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.
Melonenobjekt hinzufügen
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.
Versuchen Sie zum Schluss, ein 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.
Aber warte was ist, wenn jemand beschließt, einen neuen Zitronentyp zu erstellen, sagen wir aus Gründen von SaltyLemon wie
public class SaltyLemon extends Lemon{}
Jetzt kann fruitExtendedList eine Liste von Früchten, Melonen, Wassermelonen oder Salzigen Zitronen sein.
Also unsere Aussage
fruitExtendedList.add(new WaterMelon())
ist auch nicht gültig.
Grundsätzlich können wir sagen, dass wir nichts in eine fruitExtendedList schreiben können.
Dies fasst List<? extends Fruit>
Nun wollen wir mal sehen
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 können Melonen, Wassermelonen oder andere Objekte nicht gelesen werden.
Beachten Sie jedoch, dass wir Objekttypinstanzen 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 festzulegen.
Objekttyp Objekt hinzufügen
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 Obsttyp-Objekts
melonSuperList.add(new Fruit())
//This is also not valid as melonSuperList can be list of Melon
Melonen-Objekt hinzufügen
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.
Objekt vom Typ WaterMelon hinzufügen
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 den Objekttyp object lesen.
super ist eine Untergrenze und erstreckt sich über eine Obergrenze.
Gemäß http://download.Oracle.com/javase/tutorial/extra/generics/morefun.html :
Die Lösung ist die Verwendung einer Form von Begrenzte Wildcard, die wir noch nicht gesehen haben: Wildcards mit einer unteren Schranke. Das Syntax ? Super T bezeichnet eine unbekannte Typ, der ein Supertyp von T ist (oder T selbst; denken Sie daran, dass die Relation von Supertyp reflexiv ist) Es ist das duale der begrenzten Platzhalter waren wir verwenden, wo verwenden wir? erweitert T auf bezeichnen einen unbekannten Typ, der eine .__ ist. Untertyp von T.
Ich möchte den Unterschied visualisieren. Angenommen, wir haben:
class A { }
class B extends A { }
class C extends B { }
List<? extends T>
- Lesen und Zuweisen:
|-------------------------|-------------------|---------------------------------|
| 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:
Object
aus einer Liste unabhängig vom Platzhalter erhalten.null
.Mit extend können Sie nur aus der Sammlung abrufen. Sie können nicht hineinstecken. Obwohl super sowohl get als auch put erlaubt, ist der Rückgabetyp während des get-Vorgangs ? Super T.
Das Verwirrendste dabei ist, dass die Zuweisung nur für eine Art funktioniert:
baseClassInstance = derivedClassInstance;
Sie denken vielleicht, dass Integer extends Number
und dass eine Integer
als <? extends Number>
fungieren würde, aber der Compiler wird Ihnen sagen, dass <? extends Number> cannot be converted to Integer
(dh in menschlicher Sprache) es ist falsch, dass alles, was die Zahl erweitert, in Integer umgewandelt werden kann:
class Holder<T> {
T v;
T get() { return v; }
void set(T n) { v=n; }
}
class A {
public static void main(String[]args) {
Holder<? extends Number> he = new Holder();
Holder<? super Number> hs = new Holder();
Integer i;
Number n;
Object o;
// Producer Super: always gives an error except
// when consumer expects just Object
i = hs.get(); // <? super Number> cannot be converted to Integer
n = hs.get(); // <? super Number> cannot be converted to Number
// <? super Number> cannot be converted to ... (but
// there is no class between Number and Object)
o = hs.get();
// Consumer Super
hs.set(i);
hs.set(n);
hs.set(o); // Object cannot be converted to <? super Number>
// Producer Extends
i = he.get(); // <? extends Number> cannot be converted to Integer
n = he.get();
o = he.get();
// Consumer Extends: always gives an error
he.set(i); // Integer cannot be converted to <? extends Number>
he.set(n); // Number cannot be converted to <? extends Number>
he.set(o); // Object cannot be converted to <? extends Number>
}
}
hs.set(i);
ist in Ordnung, weilInteger
IN EINE BELIEBIGE SUPERKLASSE VON Number
konvertiert werden kann (und nicht weil Integer
eine Superklasse von Number
ist, was nicht wahr ist).
EDIT hat einen Kommentar zu Consumer Extends und Producer Super hinzugefügt - sie sind nicht aussagekräftig, weil sie entsprechend nichts und nurObject
angeben. Es wird empfohlen, sich an PECS zu erinnern, da CEPS niemals nützlich ist.
Wann werden Erweiterungen und Super verwendet?
Platzhalter sind in Methodenparametern am nützlichsten. Sie ermöglichen die notwendige Flexibilität bei Methodenschnittstellen.
Menschen sind oft verwirrt, wenn sie Erweiterungen verwenden und wann sie Supergrenzen verwenden. Die Faustregel ist das Get-Put-Prinzip. Wenn Sie etwas aus einem parametrisierten Container erhalten, verwenden Sie extend.
int totalFuel(List<? extends Vehicle> list) {
int total = 0;
for(Vehicle v : list) {
total += v.getFuel();
}
return total;}
Die Methode totalFuel ruft Fahrzeuge aus der Liste ab, fragt sie nach dem verfügbaren Kraftstoff und berechnet die Summe ..__ Wenn Sie Objekte in einen parametrisierten Container legen, verwenden Sie super.
int totalValue(Valuer<? super Vehicle> valuer) {
int total = 0;
for(Vehicle v : vehicles) {
total += valuer.evaluate(v);
}
return total;}
Mit der Methode totalValue wird Vehicles in den Valuer ..__ eingefügt. Es ist nützlich zu wissen, dass Dehnungsbegrenzung viel häufiger ist als super.
Die aufgestimmten Antworten umfassen Details zu vielen Aspekten. Ich würde jedoch versuchen, dies anders zu beantworten.
Es gibt zwei Dinge, die wir berücksichtigen müssen,
List<? extends X> listvar;
Hier kann jeder Liste von X oder Liste von Unterklassen von X listvar zugewiesen werden.
List<? extends Number> listvar;
listvar = new ArrayList<Number>();
listvar = new ArrayList<Integer>();
List<? super X> listvar;
Hier kann jeder Liste von X oder Liste von Oberklassen von X listvar zugewiesen werden.
List<? super Number> listvar;
listvar = new ArrayList<Number>();
listvar = new ArrayList<Object>();
`List<? extends X> listvar;`
Sie können diese Funktion verwenden, um eine Liste in Methodenargumenten zu akzeptieren und alle Operationen an type X auszuführen (Hinweis: Sie können nur Objekte vom Typ X aus der Liste lesen).
`List<? super Number> listvar;
Sie können diese Funktion verwenden, um eine Liste in Methodenargumenten zu akzeptieren und alle Operationen an Typ Object auszuführen, da Sie nur Objekte vom Typ Object aus der Liste lesen können. Aber ja, zusätzlich können Sie Objekte vom Typ X in die Liste aufnehmen.
Liste <? erweitert X> erlaubt nicht, der Liste nichts außer null hinzuzufügen.
Liste <? super X> erlaubt das Hinzufügen von allem, was ein -X ist (X oder seine Unterklasse) oder null.
Sie können alle obigen Antworten durchgehen, um zu verstehen, warum die .add()
auf '<?>'
, '<? extends>'
und teilweise auf '<? super>'
beschränkt ist.
Aber hier ist das Fazit, wenn Sie sich daran erinnern wollen und nicht jedes Mal die Antwort untersuchen wollen:
List<? extends A>
bedeutet, dass dies jede List
von A
und Unterklasse von A
akzeptiert. Sie können jedoch nichts zu dieser Liste hinzufügen. Nicht einmal Objekte vom Typ A
.
List<? super A>
bedeutet, dass dies jede Liste von A
und Oberklasse von A
..__ akzeptiert. Sie können Objekte vom Typ A
und deren Unterklassen hinzufügen.
Die generischen Platzhalter richten sich an zwei Hauptbedürfnisse:
Lesen aus einer generischen Sammlung Einfügen in eine generische Sammlung Es gibt drei Möglichkeiten, eine Sammlung (Variable) mit generischen Platzhaltern zu definieren. Diese sind:
List<?> listUknown = new ArrayList<A>();
List<? extends A> listUknown = new ArrayList<A>();
List<? super A> listUknown = new ArrayList<A>();
List<?>
bedeutet eine Liste, deren Typ unbekannt ist. Dies könnte ein List<A>
, ein List<B>
, ein List<String>
usw. sein.
List<? extends A>
bedeutet eine Liste von Objekten, bei denen es sich um Instanzen von class A
oder subclasses of A
(z. B. B und C) handeltList<? super A>
bedeutet, dass die Liste entweder in A class
oder superclass of A
eingegeben wird.
Lesen Sie mehr: http://tutorials.jenkov.com/Java-generics/wildcards.html
|
v
Liste <? erweitert X> ? kann entweder eine beliebige Unterklasse von
X
oder sich selbstX
sein.Liste <? super X> ? kann entweder eine beliebige superclass von
X
oder sich selbstX
sein.
^
|
Beispiel, Die Reihenfolge der Vererbung wird als O> S> T> U> V angenommen
Schlüsselwörter verwenden,
Richtig:
List<? extends T> Object = new List<T>();
List<? extends T> Object = new List<U>();
List<? extends T> Object = new List<V>();
Falsch:
List<? extends T> Object = new List<S>();
List<? extends T> Object = new List<O>();
super Stichwort:
Richtig:
List<? super T> Object = new List<T>();
List<? super T> Object = new List<S>();
List<? super T> Object = new List<O>();
Falsch:
List<? super T> Object = new List<U>();
List<? super T> Object = new List<V>();
Objekt hinzufügen: List Object = new List ();
Object.add(new T()); //error
Aber warum Fehler? Schauen wir uns die Möglichkeiten der Initialisierung von Listenobjekten an
List<? extends T> Object = new List<T>();
List<? extends T> Object = new List<U>();
List<? extends T> Object = new List<V>();
Wenn wir Object.add verwenden (neues T ()); dann ist es nur korrekt wenn
List<? extends T> Object = new List<T>();
Es gibt jedoch zwei zusätzliche Möglichkeiten
List Object = new List (); List Object = new List (); Wenn wir versuchen, den beiden obigen Möglichkeiten (new T()) hinzuzufügen, wird ein Fehler ausgegeben, da T ist die übergeordnete Klasse von U und V. Wir versuchen, ein T-Objekt [das ist (new T())]] zur Liste des Typs U und V hinzuzufügen. Objekt höherer Klasse (Basisklasse) kann nicht an Object (Unterklasse) niedrigerer Klasse übergeben werden.
Aufgrund der zwei zusätzlichen Möglichkeiten gibt Java Fehler, auch wenn Sie die richtige Möglichkeit verwenden, da Java nicht weiß, auf welches Objekt Sie sich beziehen. Sie können also keine Objekte zu List Object = new List () hinzufügen. da es Möglichkeiten gibt, die nicht gültig sind.
Objekt hinzufügen: List Object = new List ();
Object.add(new T()); // compiles fine without error
Object.add(new U()); // compiles fine without error
Object.add(new V()); // compiles fine without error
Object.add(new S()); // error
Object.add(new O()); // error
Aber warum tritt ein Fehler in den beiden obigen Punkten auf? Wir können Object.add (new T ()) verwenden. nur auf die unten genannten Möglichkeiten,
List<? super T> Object = new List<T>();
List<? super T> Object = new List<S>();
List<? super T> Object = new List<O>();
Wenn wir versuchten, Object.add (new T()) in .__ zu verwenden. Listenobjekt = neue Liste (); und Listenobjekt = neue Liste (); dann wird ein Fehler ausgegeben .__ Dies ist, weil Wir können kein T-Objekt [welches neues T ()] zu dem List-Objekt = new List () hinzufügen; weil es ein Objekt vom Typ U ist. Wir können U-Objekten kein T-Objekt [neues T ()] hinzufügen, da T eine Basisklasse und U eine Unterklasse ist. Wir können der Unterklasse keine Basisklasse hinzufügen, und deshalb tritt ein Fehler auf. Dies gilt auch für den anderen Fall.