Untuk memahami kovarians dan kontravarians, kita mesti terlebih dahulu memperkenalkan:
Menurut prinsip penggantian Liskov, jika C ialah subkelas P, maka P boleh menggantikan C, iaitu P p = baharu C();
C mewarisi daripada P, dilambangkan sebagai C < P
Jika F adalah invarian , apabila C <= P, maka F(C) dan F(P) tidak mempunyai hubungan warisan
Kecuali sebagai contoh, Integer ialah subkelas Nombor, mengikut prinsip penggantian Liskov
Number number = new Integer(1); //correct
Tetapi jika anda menulis seperti ini, ralat akan dilaporkan
List<Number> list = new ArrayList<Integer>(1); //error
Walaupun Nombor dan Integer mempunyai hubungan warisan: Nombor Integer < dianggap sebagai List<Number>
Tiada hubungan pewarisan dengan List<Integer>
Jika F ialah kovarian, apabila C <= P, maka F(C) < = F(P)
Java menyediakan lanjutan untuk menukar invarian kepada kovarians, contohnya:
List<? extends Number> list = new ArrayList<Integer>(1); //corrent
Pada masa ini, List<? extends Number>
boleh Dilihat sebagai kelas induk ArrayList<Integer>
,
? extend Number
boleh dilihat sebagai julat jenis, mewakili subkelas Nombor tertentu Tatasusunan
ialah kovarian secara lalai
Number[] numbers = new Integer[3];
Jika F adalah kontravarian, apabila C <= P, maka F(C) >= F(P)
Java menyediakan super untuk menukar invarian kepada kovarians, contohnya:
List<? super Number> list = new ArrayList<Object>(1); //corrent
Pada masa ini, List<? super Number>
boleh dianggap sebagai kelas induk bagi ArrayList<Object>
Pertama, mari kita lihat pelaksanaan Collection.add:
public interface List<E> extends Collection<E> { boolean add(E e); }
Adakah kod berikut melaporkan ralat? ? extends Number
tidak sepadan dengan jenis Integer
List<? extends Number> list = new ArrayList<Integer>(); // correct list.add(Integer.valueOf(1)); //error
Pertama, apabila memanggil kaedah tambah, E
generik secara automatik menjadi <? extends Number>
dan ralat dilaporkan pada baris kedua. Dengan kata lain, ? extends Number
bukan kelas induk Integer
. Di sini kita perlu membezakan bahawa List<? extends Number>
ialah kelas induk ArrayList<Integer>
.
? extends Number
boleh dianggap sebagai jenis tertentu dalam julat jenis, mewakili subkelas Nombor tertentu, tetapi tidak jelas subkelas mana ia mungkin Terapung, mungkin Pendek atau ia mungkin Subkelas (Integer diubah suai oleh muktamad, tidak ada subkelas yang mungkin, ini hanyalah situasi hipotesis), ia hanya menentukan sempadan atasnya sebagai Nombor, dan tidak menentukan sempadan bawah (mungkin terdapat ? extends Number
<. ; Integer
) , oleh itu ? extends Number
bukan kelas induk Integer
Ubah suai sedikit kod di atas dan ia akan betul:
List<? super Number> list = new ArrayList<Object>(); // correct list.add(Integer.valueOf(1)); //correct
Pertama daripada semua, kerana penyongsangan, List<? super Number>
ialah Kelas induk ArrayList<Object>
, baris pertama adalah betul.
Baris kedua: ? super Number
ialah kelas induk Integer
, sebabnya ialah: ? super Number
mewakili kelas induk Nombor tertentu, ia mungkin Serializable
atau Object
tetapi tidak kira yang mana satu , kelas induk Nombor mestilah kelas induk Integer, jadi baris kedua juga betul
public static <T> void copy(List<? super T> dest, List<? extends T> src) { int srcSize = src.size(); if (srcSize > dest.size()) throw new IndexOutOfBoundsException("Source does not fit in dest"); if (srcSize < COPY_THRESHOLD || (src instanceof RandomAccess && dest instanceof RandomAccess)) { for (int i=0; i<srcSize; i++) dest.set(i, src.get(i)); } else { ListIterator<? super T> di=dest.listIterator(); ListIterator<? extends T> si=src.listIterator(); for (int i=0; i<srcSize; i++) { di.next(); di.set(si.next()); } } }
private static <E> E getFirst(List<? extends E> list){ return list.get(0); } private static <E> void setFirst(List<? super E> list, E firstElement){ list.add(firstElement); } public static void main(String[] args) { List<Integer> list = new ArrayList<Integer>(); setFirst(list, 1); Number number = getFirst(list); }
Atas ialah kandungan terperinci Kaedah kovarian, kontravarian, lanjutan dan pemilihan super generik Java. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!