wake-up-neo.net

Unterschied zwischen <? super T> und <? erweitert T> in Java

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.

658
Anand

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
  1. Reading - Unter Berücksichtigung der oben genannten möglichen Zuordnungen, welchen Objekttyp Sie garantiert aus List foo3 lesen können:

    • Sie können eine Number lesen, da jede der Listen, die foo3 zugewiesen werden könnten, eine Number oder eine Unterklasse von Number enthält.
    • Sie können eine Integer nicht lesen, da foo3 auf einen List<Double> zeigen könnte.
    • Sie können eine Double nicht lesen, da foo3 auf einen List<Integer> zeigen könnte.
  2. 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:

    • Sie können keine Integer hinzufügen, da foo3 auf einen List<Double> zeigen könnte.
    • Sie können keine Double hinzufügen, da foo3 auf einen List<Integer> zeigen könnte.
    • Sie können keine 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
  1. Reading - Welche Art von Objekt erhalten Sie aufgrund der oben genannten möglichen Zuweisungen garantiert, wenn Sie von List foo3 lesen:

    • Eine Integer ist nicht garantiert, da foo3 auf List<Number> oder List<Object> zeigen könnte.
    • Eine Number ist nicht garantiert, da foo3 auf einen List<Object> zeigen könnte.
    • Die Garantie von only besteht darin, dass Sie eine Instanz einer Object oder einer Unterklasse von Object erhalten (Sie wissen jedoch nicht, welche Unterklasse).
  2. 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:

    • Sie können eine Integer hinzufügen, da in einer der obigen Listen eine Integer zulässig ist.
    • Sie können eine Instanz einer Unterklasse von Integer hinzufügen, da eine Instanz einer Unterklasse von Integer in einer der obigen Listen zulässig ist.
    • Sie können keine Double hinzufügen, da foo3 auf einen ArrayList<Integer> zeigen könnte.
    • Sie können keine Number hinzufügen, da foo3 auf einen ArrayList<Integer> zeigen könnte.
    • Sie können keine Object hinzufügen, da foo3 auf einen ArrayList<Integer> zeigen könnte.

PECS

Denken Sie an PECS: "Producer erweitert, Consumer Super".

  • "Producer Extends" - Wenn Sie eine List benötigen, um T-Werte zu erzeugen (Sie möchten Ts 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 Ts 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>.

Beispiel

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?

1235
Bert F

Stellen Sie sich vor, Sie hätten diese Hierarchie

 enter image description here

1. erweitert

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):

  1. C2:new ArrayList<C2>(); (ein Objekt, das C2 oder Untertypen speichern kann) oder
  2. D1:new ArrayList<D1>(); (ein Objekt, das D1 oder Untertypen speichern kann) oder
  3. D2:new 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

 enter image description here

Wie Sie sehen, gibt es kein sicherer Typ, das in jedem Fall gleich ist:

  • sie können nicht list.add(new C2(){});, da es list = new ArrayList<D1>(); sein könnte
  • sie können nicht list.add(new D1(){});, da es list = new ArrayList<D2>(); sein könnte

und so weiter. 

2. Super

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:

  • A1:new ArrayList<A1>(); (ein Objekt, das A1 oder Untertypen speichern kann) oder
  • A2:new ArrayList<A2>(); (ein Objekt, das A2 oder Untertypen speichern kann) oder
  • A3:new 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

 enter image description here

Wie Sie sehen, haben wir hier sieben sichere Typen, die in jedem Fall gleich sind: C2, D1, D2, E1, E2, E3, E4.

  • sie können list.add(new C2(){}); verwenden, da C2 unabhängig von der Art der Liste, auf die wir uns beziehen, zulässig ist
  • sie können list.add(new D1(){}); verwenden, da D1 unabhängig von der Art der Liste, auf die wir uns beziehen, zulässig ist

und so weiter. Sie haben wahrscheinlich bemerkt, dass diese Typen der Hierarchie entsprechen, beginnend mit dem Typ C2.

Anmerkungen

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{}
191
Luigi Cortese

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.

77

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.

18
Sushant

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.

14
Istao

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:

  • sie können immer Object aus einer Liste unabhängig vom Platzhalter erhalten.
  • sie können der variablen Liste unabhängig vom Platzhalter immer hinzufügennull.
8
Oleksandr

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.

3
Sai Sunder

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 Numberkonvertiert 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 nurObjectangeben. 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.

1
Kevin STS

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, 

1. Zuordnung zur Listenvariablen

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>();

2. Führen Sie die Lese- oder Schreiboperation für die Listenvariable aus

`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.

1

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.

1
elyor

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.

1
jforex78

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

1
Vaibhav Gupta
                                       |
                                       v

Liste <? erweitert X> ? kann entweder eine beliebige Unterklasse von X oder sich selbst X sein.

Liste <? super X> ? kann entweder eine beliebige superclass von X oder sich selbst X sein.

                                      ^
                                      |
0
snr

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.

0
Crox