Nennen Sie Beispiele für Funktionen, die Kovarianz und Kontravarianz sowohl bei Überladung als auch bei Überschreibung in Java demonstrieren. [geschlossen]

Antworten:

154

Kovarianz:

class Super {
  Object getSomething(){}
}
class Sub extends Super {
  String getSomething() {}
}

Sub # getSomething ist kovariant, da es eine Unterklasse des Rückgabetyps von Super # getSomething zurückgibt (aber den Vertrag von Super.getSomething () erfüllt).

Kontravarianz

class Super{
  void doSomething(String parameter)
}
class Sub extends Super{
  void doSomething(Object parameter)
}

Sub # doSomething ist kontravariant, da es einen Parameter einer Oberklasse des Parameters von Super # doSomething verwendet (aber auch hier den Vertrag von Super # doSomething erfüllt).

Hinweis: Dieses Beispiel funktioniert nicht in Java. Der Java-Compiler würde die doSomething () - Methode überladen und nicht überschreiben. Andere Sprachen unterstützen diesen Stil der Kontravarianz.

Generika

Dies ist auch für Generika möglich:

List<String> aList...
List<? extends Object> covariantList = aList;
List<? super String> contravariantList = aList;

Sie können jetzt auf alle Methoden zugreifen, für covariantListdie kein generischer Parameter erforderlich ist (da es sich um etwas handeln muss, das "Objekt erweitert"), aber Getter funktionieren einwandfrei (da das zurückgegebene Objekt immer vom Typ "Objekt" ist).

Das Gegenteil gilt für contravariantList: Sie können auf alle Methoden mit generischen Parametern zugreifen (Sie wissen, dass es sich um eine Oberklasse von "String" handeln muss, damit Sie immer eine übergeben können), aber keine Getter (Der zurückgegebene Typ kann von einem anderen Supertyp von String sein )

Hardcodiert
quelle
79
Das erste Beispiel für Kontravarianz funktioniert in Java nicht. doSomething () in der Sub-Klasse ist eine Überladung, keine Überschreibung.
Craig P. Motlin
15
Tatsächlich. Java unterstützt keine kontravarianten Argumente bei der Subtypisierung. Nur Kovarianz für die Rückgabetypen der Methode (wie im ersten Beispiel).
the_dark_destructor
Gute Antwort. Kovarianz erscheint mir logisch. Aber können Sie mir einen Absatz in JLS zeigen, der die Kontravarianz beschreibt? Warum wird Sub.doSomething aufgerufen?
Mikhail
2
Wie Craig betonte, ist es nicht. Ich denke, hier gibt es einen Konflikt zwischen Überschreiben und Überladen, und SUN hat (wie immer) die abwärtskompatible Option gewählt. In Java können Sie daher keine kontravarianten Parameter verwenden, wenn Sie eine Methode überschreiben.
Hardcoded
1
Wäre schön zu wissen, warum ich für meine Antwort Downvotes bekomme.
Hardcoded
48

Ko-Varianz: Iterierbar und Iterator. Es ist fast immer sinnvoll, eine Co-Variante Iterableoder zu definieren Iterator. Iterator<? extends T>kann genauso verwendet werden wie Iterator<T>- der einzige Ort, an dem der Typparameter angezeigt wird, ist der Rückgabetyp der nextMethode, sodass er sicher auf den neuesten Stand gebracht werden kann T. Wenn Sie jedoch SErweiterungen haben T, können Sie auch Iterator<S>eine Variable vom Typ zuweisen Iterator<? extends T>. Zum Beispiel, wenn Sie eine Suchmethode definieren:

boolean find(Iterable<Object> where, Object what)

Sie können es nicht mit List<Integer>und aufrufen 5, daher ist es besser definiert als

boolean find(Iterable<?> where, Object what)

Gegenvarianz: Komparator. Es ist fast immer sinnvoll zu verwenden Comparator<? super T>, da es genauso verwendet werden kann Comparator<T>. Der Typparameter wird nur als compareMethodenparametertyp angezeigt und Tkann daher sicher an ihn übergeben werden. Wenn Sie beispielsweise eine haben DateComparator implements Comparator<java.util.Date> { ... }und eine List<java.sql.Date>mit diesem Komparator sortieren möchten ( java.sql.Dateeine Unterklasse von java.util.Date), können Sie Folgendes tun:

<T> void sort(List<T> what, Comparator<? super T> how)

aber nicht mit

<T> void sort(List<T> what, Comparator<T> how)
Yardena
quelle
-4

Schauen Sie sich das Liskov-Substitutionsprinzip an . Wenn Klasse B Klasse A erweitert, sollten Sie in der Lage sein, ein B zu verwenden, wenn ein A erforderlich ist.

Extraneon
quelle
6
Dies beantwortet die Frage nicht und ist irreführend. Es wäre durchaus möglich, ein Variantensystem zu entwerfen, das die semantische Korrektheit bricht und daher gegen LSP verstößt.
Matt Whipple
das ist zum Beispiel nicht der Fall contra variant. super.doSomething("String")konnte nicht ersetzt werden durch sub.doSomething(Object).
Zinking
Es ist nicht die Frage
OlivierTerrien