Rumah > Java > javaTutorial > teks badan

Kaedah kovarian, kontravarian, lanjutan dan pemilihan super generik Java

PHPz
Lepaskan: 2023-05-26 13:46:12
ke hadapan
1295 orang telah melayarinya

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

Apakah invarian

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
Salin selepas log masuk

Tetapi jika anda menulis seperti ini, ralat akan dilaporkan

List<Number> list = new ArrayList<Integer>(1);  //error
Salin selepas log masuk

Walaupun Nombor dan Integer mempunyai hubungan warisan: Nombor Integer < dianggap sebagai List<Number> Tiada hubungan pewarisan dengan List<Integer>

Apakah kovarians

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
Salin selepas log masuk

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];
Salin selepas log masuk

Apakah kontravarian

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
Salin selepas log masuk

Pada masa ini, List<? super Number> boleh dianggap sebagai kelas induk bagi ArrayList<Object>

melanjutkan dan super

Pertama, mari kita lihat pelaksanaan Collection.add:

public interface List<E> extends Collection<E> { boolean add(E e); }
Salin selepas log masuk

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
Salin selepas log masuk

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
Salin selepas log masuk

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

Perlukah saya menggunakan extends atau super? java.util.Collections (JDK1.7 ) memberi kami jawapan:

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());
        }
    }
}
Salin selepas log masuk

Apabila anda ingin mendapatkan data daripada kelas generik, gunakan extends; >
  • Untuk mendapatkan data daripada kelas generik Semasa menulis data dalam kelas, gunakan super; kad bebas (iaitu, lanjutan atau super tidak digunakan)

  • 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);
    }
    Salin selepas log masuk

    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!

Label berkaitan:
sumber:yisu.com
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan