Jawaban:
Kovarian:
class Super {
Object getSomething(){}
}
class Sub extends Super {
String getSomething() {}
}
Sub # getSomething adalah kovarian karena mengembalikan subclass dari tipe kembalian Super # getSomething (tetapi memenuhi kontrak Super.getSomething ())
Kontravarian
class Super{
void doSomething(String parameter)
}
class Sub extends Super{
void doSomething(Object parameter)
}
Sub # doSomething adalah contravariant karena mengambil parameter superclass dari parameter Super # doSomething (tapi, sekali lagi, memenuhi kontrak Super # doSomething)
Perhatikan: contoh ini tidak berfungsi di Java. Compiler Java akan membebani dan tidak mengganti metode doSomething () -. Bahasa lain mendukung gaya kontravarian ini.
Generik
Ini juga mungkin untuk Generik:
List<String> aList...
List<? extends Object> covariantList = aList;
List<? super String> contravariantList = aList;
Anda sekarang dapat mengakses semua metode covariantList
yang tidak mengambil parameter umum (karena harus berupa sesuatu yang "memperluas Objek"), tetapi getter akan berfungsi dengan baik (karena objek yang dikembalikan akan selalu berjenis "Objek")
Hal yang sebaliknya berlaku untuk contravariantList
: Anda dapat mengakses semua metode dengan parameter generik (Anda tahu itu pasti kelas super dari "String", sehingga Anda selalu dapat meneruskan satu), tetapi tidak ada getter (Jenis yang dikembalikan mungkin dari supertipe String lainnya )
Co-variance: Iterable dan Iterator. Hampir selalu masuk akal untuk mendefinisikan co-varian Iterable
atau Iterator
. Iterator<? extends T>
dapat digunakan sama seperti Iterator<T>
- satu-satunya tempat di mana parameter tipe muncul adalah tipe kembalian dari next
metode, sehingga dapat dengan aman di-up-cast T
. Tetapi jika Anda memiliki S
perluasan T
, Anda juga dapat menetapkan Iterator<S>
ke tipe variabel Iterator<? extends T>
. Misalnya jika Anda mendefinisikan metode find:
boolean find(Iterable<Object> where, Object what)
Anda tidak akan dapat memanggilnya dengan List<Integer>
dan 5
, jadi lebih baik didefinisikan sebagai
boolean find(Iterable<?> where, Object what)
Kontra-varian: Pembanding. Hampir selalu masuk akal untuk digunakan Comparator<? super T>
, karena dapat digunakan sama seperti Comparator<T>
. Parameter tipe muncul hanya sebagai compare
tipe parameter metode, sehingga T
dapat diteruskan dengan aman. Misalnya jika Anda memiliki DateComparator implements Comparator<java.util.Date> { ... }
dan ingin mengurutkan List<java.sql.Date>
dengan pembanding itu ( java.sql.Date
adalah sub-kelas dari java.util.Date
), Anda dapat melakukannya dengan:
<T> void sort(List<T> what, Comparator<? super T> how)
tapi tidak dengan
<T> void sort(List<T> what, Comparator<T> how)
Lihatlah prinsip substitusi Liskov . Akibatnya, jika kelas B memperluas kelas A maka Anda harus dapat menggunakan B setiap kali A diperlukan.
contra variant
dikatakan. super.doSomething("String")
tidak bisa digantikan oleh sub.doSomething(Object)
.