1047 Stimmen

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

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.

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.

4voto

18446744073709551615 Punkte 15274

Das Verwirrendste an der Sache ist, dass die Zuweisung unabhängig von den angegebenen Typbeschränkungen nur in eine Richtung funktioniert:

baseClassInstance = derivedClassInstance;

Sie denken vielleicht, dass Integer extends Number und dass ein Integer tun würde als <? extends Number> aber der Compiler wird Ihnen sagen, dass <? extends Number> cannot be converted to Integer (das heißt, im menschlichen Sprachgebrauch, 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, weil Integer kann in jede Oberklasse von Number (und nicht weil Integer ist eine Oberklasse von Number was nicht der Fall ist).

EDIT fügte eine Bemerkung zu Consumer Extends und Producer Super hinzu - sie sind nicht sinnvoll, weil sie entsprechend angeben, nichts und einfach Object . Wir raten Ihnen, sich PECS zu merken, denn CEPS ist nie nützlich.

2voto

Crox Punkte 41

Beispiel, Die Reihenfolge der Vererbung wird angenommen als O > S > T > U > V

Mit erweitert Schlüsselwort ,

Richtig:

List<? extends T> Object = new List<T>();
List<? extends T> Object = new List<U>();
List<? extends T> Object = new List<V>();

InCorrect:

List<? extends T> Object = new List<S>();
List<? extends T> Object = new List<O>();

super Schlüsselwort:

Richtig:

List<? super T> Object = new List<T>();
List<? super T> Object = new List<S>();
List<? super T> Object = new List<O>();

InCorrect:

List<? super T> Object = new List<U>();
List<? super T> Object = new List<V>();

Objekt hinzufügen: Liste Object = new List();

Object.add(new T()); //error

Aber warum Fehler? Schauen wir uns die Möglichkeiten der Initialisierungen von List Object 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(new T()); verwenden, dann ist es nur korrekt, wenn

List<? extends T> Object = new List<T>(); 

Aber es gibt noch zwei weitere Möglichkeiten

Liste Object = new List(); List Object = new List(); Wenn wir versuchen, (new T()) zu den beiden oben genannten Möglichkeiten hinzuzufügen, wird es einen Fehler geben, weil T die übergeordnete Klasse von U und V ist. Wir versuchen, ein T-Objekt [das (new T()) ist] zu List vom Typ U und V hinzuzufügen. Ein Objekt höherer Klasse (Basisklasse) kann nicht an ein Objekt niedrigerer Klasse (Unterklasse) übergeben werden.

Aufgrund der zwei zusätzlichen Möglichkeiten gibt Java eine Fehlermeldung aus, selbst 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: Liste 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 der Fehler bei den beiden oben genannten auf? Wir können Object.add(new T()); nur bei den unten genannten Möglichkeiten verwenden,

List<? super T> Object = new List<T>();
List<? super T> Object = new List<S>();
List<? super T> Object = new List<O>();

Wenn wir versuchen würden, Object.add(new T()) in Liste Object = new List(); und Liste Object = new List(); dann wird ein Fehler ausgegeben Der Grund dafür ist Wir können kein T-Objekt [welches new T()] zu List Object = new List(); hinzufügen, weil es ein Objekt vom Typ U ist. Wir können kein T-Objekt [welches new T()] zu U Object hinzufügen, weil T eine Basisklasse und U eine Unterklasse ist. Wir können keine Basisklasse zu einer Unterklasse hinzufügen und deshalb tritt der Fehler auf. Dies gilt auch für den anderen Fall.

1voto

Vaibhav Gupta Punkte 965

Die generischen Platzhalter zielen auf zwei Hauptbedürfnisse ab:

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, die auf einen unbekannten Typ typisiert ist. Dies könnte eine List<A> , a List<B> , a List<String> usw.

List<? extends A> bedeutet eine Liste von Objekten, die Instanzen der class A , oder subclasses of A (z. B. B und C). List<? super A> bedeutet, dass die Liste entweder in den A class oder eine superclass of A .

Lesen Sie mehr : http://tutorials.jenkov.com/java-generics/wildcards.html

1voto

Kevin STS Punkte 133

Wann man extends und super verwendet

Wildcards sind vor allem in Methodenparametern nützlich. Sie ermöglichen die notwendige Flexibilität bei Methodenschnittstellen.

Die Leute sind oft verwirrt, wenn sie extends und wenn sie super bounds verwenden sollen. Als Faustregel gilt das Get-Put-Prinzip. Wenn Sie etwas von einem parametrisierten Container erhalten, verwenden Sie extends.

int totalFuel(List<? extends Vehicle> list) {
int total = 0;
for(Vehicle v : list) {
    total += v.getFuel();
}
return total;}

Die Methode totalFuel holt sich die Fahrzeuge aus der Liste, fragt sie nach ihrem Treibstoffvorrat und berechnet die Summe. Wenn Sie Objekte in einen parametrisierten Container setzen, verwenden Sie super.

int totalValue(Valuer<? super Vehicle> valuer) {
int total = 0;
for(Vehicle v : vehicles) {
    total += valuer.evaluate(v);
}
return total;}

Die Methode totalValue setzt Fahrzeuge in den Valuer. Es ist nützlich zu wissen, dass extends bound viel häufiger vorkommt als super.

CodeJaeger.com

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.

Powered by:

X