Heute habe ich einige Artikel über Kovarianz, Kontravarianz (und Invarianz) in Java gelesen. Ich habe den englischen und deutschen Wikipedia-Artikel sowie einige andere Blog-Beiträge und Artikel von IBM gelesen.
Aber ich bin immer noch ein bisschen verwirrt darüber, worum es genau geht? Einige sagen, es geht um die Beziehung zwischen Typen und Untertypen, andere sagen, es geht um die Typkonvertierung und andere sagen, es wird verwendet, um zu entscheiden, ob eine Methode überschrieben oder überladen wird.
Ich suche also nach einer einfachen Erklärung im Klartext, die einem Anfänger zeigt, was Kovarianz und Kontravarianz (und Invarianz) ist. Pluspunkt für ein einfaches Beispiel.
Antworten:
Alles das oben Genannte.
Im Kern beschreiben diese Begriffe, wie die Subtypbeziehung durch Typtransformationen beeinflusst wird. Das heißt, wenn
A
undB
Typen sind,f
ist eine Typtransformation und ≤ die Subtyp-Beziehung (dhA ≤ B
bedeutet, dass diesA
ein Subtyp von istB
), die wir habenf
ist kovariant, wenn diesA ≤ B
impliziertf(A) ≤ f(B)
f
ist kontravariant, wenn diesA ≤ B
impliziertf(B) ≤ f(A)
f
ist unveränderlich, wenn keiner der oben genannten Punkte zutrifftBetrachten wir ein Beispiel. Lassen Sie,
f(A) = List<A>
wo vonList
deklariert wirdIst
f
kovariant, kontravariant oder invariant? Kovariante würde bedeuten, dass aList<String>
ein Subtyp von istList<Object>
, Kontravariante, dass aList<Object>
ein Subtyp von ist,List<String>
und Invariante, dass keiner ein Subtyp des anderen ist, dhList<String>
undList<Object>
nicht konvertierbare Typen sind. In Java ist letzteres wahr, wir sagen (etwas informell), dass Generika unveränderlich sind.Ein anderes Beispiel. Lass
f(A) = A[]
. Istf
kovariant, kontravariant oder invariant? Das heißt, ist String [] ein Subtyp von Object [], Object [] ein Subtyp von String [] oder ist keiner der Subtypen des anderen? (Antwort: In Java sind Arrays kovariant)Das war noch ziemlich abstrakt. Um es konkreter zu machen, schauen wir uns an, welche Operationen in Java in Bezug auf die Subtyp-Beziehung definiert sind. Das einfachste Beispiel ist die Zuordnung. Die Aussage
wird nur kompiliert, wenn
typeof(y) ≤ typeof(x)
. Das heißt, wir haben gerade erfahren, dass die Aussagenwird nicht in Java kompiliert, aber
werden.
Ein weiteres Beispiel, bei dem die Subtypbeziehung von Bedeutung ist, ist ein Methodenaufrufausdruck:
Informell gesehen wird diese Anweisung ausgewertet, indem dem
a
ersten Parameter der Methode der Wert von zugewiesen wird, dann der Hauptteil der Methode ausgeführt wird und anschließend der Rückgabewert der Methode zugewiesen wirdresult
. Wie die einfache Zuordnung im letzten Beispiel muss die "rechte Seite" ein Untertyp der "linken Seite" sein, dh diese Aussage kann nur gültig sein, wenntypeof(a) ≤ typeof(parameter(method))
undreturntype(method) ≤ typeof(result)
. Das heißt, wenn die Methode deklariert ist durch:Keiner der folgenden Ausdrücke wird kompiliert:
aber
werden.
Ein weiteres Beispiel, bei dem es auf die Subtypisierung ankommt, ist das Überschreiben. Erwägen:
wo
Informell schreibt die Laufzeit dies um in:
Damit die markierte Zeile kompiliert werden kann, muss der Methodenparameter der überschreibenden Methode ein Supertyp des Methodenparameters der überschriebenen Methode und der Rückgabetyp ein Subtyp des überschriebenen Methodens sein. Formal
f(A) = parametertype(method asdeclaredin(A))
muss es zumindest kontravariant sein undf(A) = returntype(method asdeclaredin(A))
muss zumindest kovariant sein.Beachten Sie das "mindestens" oben. Dies sind Mindestanforderungen, die jede vernünftige statisch typsichere objektorientierte Programmiersprache durchsetzen wird, aber eine Programmiersprache kann sich dafür entscheiden, strenger zu sein. Im Fall von Java 1.4 müssen Parametertypen und Methodenrückgabetypen beim Überschreiben von Methoden, dh
parametertype(method asdeclaredin(A)) = parametertype(method asdeclaredin(B))
beim Überschreiben , identisch sein (mit Ausnahme des Löschens von Typen) . Seit Java 1.5 sind beim Überschreiben kovariante Rückgabetypen zulässig, dh Folgendes wird in Java 1.5 kompiliert, jedoch nicht in Java 1.4:Ich hoffe, ich habe alles abgedeckt - oder besser gesagt, die Oberfläche zerkratzt. Trotzdem hoffe ich, dass es helfen wird, das abstrakte, aber wichtige Konzept der Typvarianz zu verstehen.
quelle
A ≤ B
. Diese Notation macht die Dinge viel einfacher und aussagekräftiger. Gute Lektüre ...Nehmen Sie das Java-Typ-System und dann Klassen:
Jedes Objekt eines Typs T kann durch ein Objekt des Subtyps T ersetzt werden.
TYP VARIANCE - KLASSENMETHODEN HABEN DIE FOLGENDEN FOLGEN
Man kann sehen, dass:
Nun beziehen sich Co und Contra auf B als Subtyp von A. Die folgenden stärkeren Typisierungen können mit spezifischerem Wissen eingeführt werden. Im Subtyp.
Kovarianz (in Java verfügbar) ist nützlich, um zu sagen, dass man im Subtyp ein spezifischeres Ergebnis zurückgibt. besonders gesehen, wenn A = T und B = S. Contravariance sagt, dass Sie bereit sind, mit einem allgemeineren Argument umzugehen.
quelle
Bei Varianz geht es um Beziehungen zwischen Klassen mit unterschiedlichen generischen Parametern. Ihre Beziehungen sind der Grund, warum wir sie besetzen können.
Co- und Contra-Varianz sind ziemlich logische Dinge. Das Sprachtypsystem zwingt uns, die Logik des wirklichen Lebens zu unterstützen. Es ist leicht anhand eines Beispiels zu verstehen.
Kovarianz
Zum Beispiel möchten Sie eine Blume kaufen und haben zwei Blumengeschäfte in Ihrer Stadt: Rosengeschäft und Gänseblümchengeschäft.
Wenn Sie jemanden fragen "Wo ist der Blumenladen?" und jemand sagt dir, wo ist Rosenladen, wäre es okay? Ja, weil Rose eine Blume ist. Wenn Sie eine Blume kaufen möchten, können Sie eine Rose kaufen. Gleiches gilt, wenn Ihnen jemand mit der Adresse des Gänseblümchenladens geantwortet hat. Dies ist beispielsweise der Kovarianz : Sie dürfen auf Guss
A<C>
zuA<B>
, woC
es eine Unterklasse vonB
, wennA
generische Werte erzeugt (kehrt als Ergebnis aus der Funktion). Bei Covariance geht es um Produzenten.Typen:
Die Frage lautet "Wo ist der Blumenladen?", Die Antwort lautet "Rosenladen dort":
Kontravarianz
Zum Beispiel möchten Sie Ihrer Freundin eine Blume schenken. Wenn Ihre Freundin eine Blume liebt, können Sie sie als eine Person betrachten, die Rosen liebt, oder als eine Person, die Gänseblümchen liebt? Ja, denn wenn sie eine Blume liebt, würde sie sowohl Rose als auch Gänseblümchen lieben. Dies ist ein Beispiel für die Kontra : Sie Guss erlaubt sind
A<B>
zuA<C>
, woC
ist Unterklasse vonB
, wennA
verbraucht generischen Wert. Bei Kontravarianz geht es um Verbraucher.Typen:
Sie betrachten Ihre Freundin, die jede Blume liebt, als jemanden, der Rosen liebt, und geben ihr eine Rose:
Weitere Informationen finden Sie an der Quelle .
quelle