905 Stimmen

Was ist PECS (Producer Extends Consumer Super)?

Ich stieß auf PECS (kurz für Produzent extends und Verbraucher super ), während ich mich über Generika informierte.

Kann mir jemand erklären, wie man PECS einsetzt, um die Verwirrung zwischen extends y super ?

6 Stimmen

Eine sehr gute Erklärung mit einem Beispiel @ youtube.com/watch?v=34oiEq9nD0M&feature=youtu.be&t=1630, das erklärt super Teil, sondern gibt eine Vorstellung von einem anderen.

10voto

mouselabs Punkte 255

Die PECS-"Regel" stellt lediglich sicher, dass das Folgende legal ist:

  • Verbraucher: was auch immer ? ist, kann sie rechtlich beziehen sich auf T
  • Produzent: was auch immer ? ist, kann es rechtlich sein genannt von T

Die typische Paarung nach dem Muster List<? extends T> producer, List<? super T> consumer ist einfach die Sicherstellung, dass der Compiler die Standardregeln für Vererbungsbeziehungen "IS-A" durchsetzen kann. Wenn wir dies rechtlich tun könnten, wäre es vielleicht einfacher zu sagen <T extends ?>, <? extends T> (oder besser noch in Scala, wie Sie oben sehen können, ist es [-T], [+T] . Leider ist das Beste, was wir tun können <? super T>, <? extends T> .

Als ich zum ersten Mal darauf gestoßen bin und es in meinem Kopf aufgeschlüsselt habe, machte die Mechanik Sinn, aber der Code selbst sah für mich weiterhin verwirrend aus - ich dachte immer wieder "es scheint, als ob die Grenzen nicht so invertiert werden müssten" - obwohl mir klar war, dass es einfach darum geht, die Einhaltung der Standard-Referenzregeln zu garantieren.

Was mir geholfen hat, war, die gewöhnliche Aufgabe als Analogie zu betrachten.

Betrachten Sie den folgenden (nicht produktionsreifen) Spielzeugcode:

// copies the elements of 'producer' into 'consumer'
static <T> void copy(List<? extends T> producer, List<? super T> consumer) {
   for(T t : producer)
       consumer.add(t);
}

Zur Veranschaulichung der Analogie der Zuteilung, für consumer die ? Platzhalter (unbekannter Typ) ist die Referenz - die "linke Seite" der Zuweisung - und <? super T> gewährleistet, dass die ? ist, T "IS-A" ? - das T zugewiesen werden, denn ? ist ein Supertyp (oder höchstens derselbe Typ) wie T .

Para producer das Anliegen ist das gleiche, nur umgekehrt: producer 's ? Platzhalter (unbekannter Typ) ist die Referent - die "rechte Seite" der Aufgabe - und <? extends T> gewährleistet, dass die ? ist, ? "IS-A" T - das es kann zugewiesen werden zu einer T denn ? ist ein Subtyp (oder zumindest derselbe Typ) wie T .

1 Stimmen

Für diejenigen, die wie ich die "IS-A"-Terminologie nicht verstanden haben: de.wikipedia.org/wiki/Is-a

0 Stimmen

@MichalVician Stellen Sie sich eine class A und eine class B mit jeweils einer einzigen definierten öffentlichen Methode - a() y b() - beziehungsweise. Wenn B extends A ist das Ergebnis, dass B enthält sowohl a() y b() . B dann "IS-A" A denn sie repräsentiert vollständig A "Schnittstelle". Aber das Gleiche kann man nicht sagen über A - A ist keine B wissen wir nur, dass B ist (mindestens) ein A da sie extends A

4voto

Farrukh Chishti Punkte 6212

Kovarianz : Untertypen akzeptieren
Kontravarianz : Supertypen akzeptieren

Kovariante Typen sind schreibgeschützt, während kontravariante Typen schreibgeschützt sind.

4voto

yoAlex5 Punkte 20661

[Kovarianz und Kontravarianz]

Sehen wir uns ein Beispiel an

public class A { }
//B is A
public class B extends A { }
//C is A
public class C extends A { }

Generics ermöglicht es Ihnen, auf sichere Weise dynamisch mit Typen zu arbeiten

//ListA
List<A> listA = new ArrayList<A>();

//add
listA.add(new A());
listA.add(new B());
listA.add(new C());

//get
A a0 = listA.get(0);
A a1 = listA.get(1);
A a2 = listA.get(2);

//ListB
List<B> listB = new ArrayList<B>();

//add
listB.add(new B());

//get
B b0 = listB.get(0);

Problem

Da Java's Collection ein Referenztyp ist, ergeben sich die nächsten Probleme:

Problem Nr. 1

//not compiled
//danger of **adding** non-B objects using listA reference
listA = listB;

*Swift's generic hat dieses Problem nicht, denn Collection ist Value type [Über] daher wird eine neue Sammlung erstellt

Problem Nr. 2

//not compiled
//danger of **getting** non-B objects using listB reference
listB = listA;

Die Lösung - Generische Wildcards

Der Platzhalter ist ein Referenztypmerkmal und kann nicht direkt instanziiert werden.

Lösung #1 <? super A> aka untere Schranke aka Kontravarianz aka Konsumenten garantiert, dass es von A und allen Oberklassen betrieben wird, deshalb ist es sicher, wenn hinzufügen.

List<? super A> listSuperA;
listSuperA = listA;
listSuperA = new ArrayList<Object>();

//add
listSuperA.add(new A());
listSuperA.add(new B());

//get
Object o0 = listSuperA.get(0);

Lösung #2

<? extends A> aka Obergrenze aka Kovarianz aka Hersteller garantiert, dass es von A und allen Unterklassen betrieben wird, deshalb ist es sicher, dass erhalten. und werfen

List<? extends A> listExtendsA;
listExtendsA = listA;
listExtendsA = listB;

//get
A a0 = listExtendsA.get(0);

3voto

Jason Punkte 491

Denken Sie daran:

Verbraucher essen Abendbrot (super); Produzent erweitert die Fabrik seiner Eltern

1voto

contrapost Punkte 643

Anhand eines Beispiels aus dem wirklichen Leben (mit einigen Vereinfachungen):

  1. Stellen Sie sich einen Güterzug mit Güterwagen als Analogie zu einer Liste vor.
  2. Sie können setzen. eine Ladung in einem Güterwagen, wenn die Ladung die gleiche oder eine kleinere Größe als der Güterwagen = <? super FreightCarSize>
  3. Sie können entladen eine Ladung aus einem Güterwagen, wenn Sie genügend Platz (mehr als die Größe der Ladung) in Ihrem Depot = <? extends DepotSize>

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