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
?
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
?
Die PECS-"Regel" stellt lediglich sicher, dass das Folgende legal ist:
?
ist, kann sie rechtlich beziehen sich auf T
?
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
.
Für diejenigen, die wie ich die "IS-A"-Terminologie nicht verstanden haben: de.wikipedia.org/wiki/Is-a
@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
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);
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;
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);
Anhand eines Beispiels aus dem wirklichen Leben (mit einigen Vereinfachungen):
<? super FreightCarSize>
<? extends DepotSize>
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.
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.