Bitte zeigen Sie ein gutes Beispiel für Kovarianz und Kontravarianz in Java.
quelle
Bitte zeigen Sie ein gutes Beispiel für Kovarianz und Kontravarianz in Java.
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 covariantList
die 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 )
Ko-Varianz: Iterierbar und Iterator. Es ist fast immer sinnvoll, eine Co-Variante
Iterable
oder zu definierenIterator
.Iterator<? extends T>
kann genauso verwendet werden wieIterator<T>
- der einzige Ort, an dem der Typparameter angezeigt wird, ist der Rückgabetyp dernext
Methode, sodass er sicher auf den neuesten Stand gebracht werden kannT
. Wenn Sie jedochS
Erweiterungen habenT
, können Sie auchIterator<S>
eine Variable vom Typ zuweisenIterator<? extends T>
. Zum Beispiel, wenn Sie eine Suchmethode definieren:Sie können es nicht mit
List<Integer>
und aufrufen5
, daher ist es besser definiert alsGegenvarianz: Komparator. Es ist fast immer sinnvoll zu verwenden
Comparator<? super T>
, da es genauso verwendet werden kannComparator<T>
. Der Typparameter wird nur alscompare
Methodenparametertyp angezeigt undT
kann daher sicher an ihn übergeben werden. Wenn Sie beispielsweise eine habenDateComparator implements Comparator<java.util.Date> { ... }
und eineList<java.sql.Date>
mit diesem Komparator sortieren möchten (java.sql.Date
eine Unterklasse vonjava.util.Date
), können Sie Folgendes tun:aber nicht mit
quelle
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.
quelle
contra variant
.super.doSomething("String")
konnte nicht ersetzt werden durchsub.doSomething(Object)
.