Rumah >Java >javaTutorial >Mengapa Senarai
> Benarkan Pelbagai Jenis Senarai Bersarang? " />
Berbilang Kad Liar pada Kaedah Generik Boleh Mengelirukan Pengkompil Java
Masalahnya:
Menggunakan berbilang kad bebas pada kaedah generik boleh menyebabkan kekeliruan untuk pengkompil Java dan pengaturcara Pertimbangkan perkara berikut contoh:
public class TwoListsOfUnknowns { static void doNothing(List<?> list1, List<?> list2) {} public static void main(String[] args) { List<String> list1 = null; List<Integer> list2 = null; doNothing(list1, list2); // compiles fine! } }
Dua kad bebas yang tidak berkaitan boleh digunakan untuk memanggil doNothing dengan Senarai
public class TwoListsOfUnknowns2 { static void doSomethingIllegal(List<?> list1, List<?> list2) { list1.addAll(list2); // DOES NOT COMPILE!!! } }
Tingkah laku ini dijangka kerana senarai1 dan senarai2 merujuk kepada jenis yang sama sekali berbeza.
Kekeliruan timbul dengan kod berikut:
public class LOLUnknowns1 { static void probablyIllegal(List<List<?>> lol, List<?> list) { lol.add(list); // this compiles!! how come??? } }
Kod ini disusun, tetapi adakah mungkin untuk mempunyai Senarai
public class LOLUnknowns2 { static void rightfullyIllegal( List<List<? extends Number>> lol, List<?> list) { lol.add(list); // DOES NOT COMPILE! As expected!!! } }
Pengkompil nampaknya menjalankan tugasnya, tetapi kekeliruan berterusan dengan variasi berikut:
public class LOLUnknowns3 { static void probablyIllegalAgain( List<List<? extends Number>> lol, List<? extends Number> list) { lol.add(list); // compiles fine!!! how come??? } }
Bukankah kod ini sepatutnya tidak dikompilkan kerana ia mungkin melibatkan Senarai
public class LOLUnknowns1a { static void probablyIllegal(List<List<?>> lol, List<?> list) { lol.add(list); // this compiles!! how come??? } public static void main(String[] args) { List<List<String>> lol = null; List<String> list = null; probablyIllegal(lol, list); // DOES NOT COMPILE!! } }
public class LOLUnknowns1b { static void probablyIllegal(List<List<?>> lol, List<?> list) { lol.add(list); // this compiles!! how come??? } public static void main(String[] args) { List<String> list = null; probablyIllegal(null, list); // compiles fine! } }Jawapannya:
Kekeliruan berpunca daripada salah faham tentang kad bebas bersarang, seperti List< ;Senarai>>, sebenarnya bermaksud. Java Generics adalah invarian, bermakna hubungan antara jenis tidak berlaku untuk instantiasi generik. Ini terpakai pada senarai bersarang juga:
Oleh itu, SenaraiA List<String> is (captureable by) a List<?>. A List<List<String>> is NOT (captureable by) a List<List<?>>. A List<List<String>> IS (captureable by) a List<? extends List<?>>.
List<List<?>> lolAny = new ArrayList<>(); lolAny.add(new ArrayList<Integer>()); lolAny.add(new ArrayList<String>());Secara ringkasan
Tingkah laku pengkompil Java dengan berbilang kad bebas generik ditentukan oleh peraturan penukaran tangkapan. Memahami had tangkapan kad bebas adalah penting untuk mengelakkan kekeliruan.
Atas ialah kandungan terperinci Mengapa Senarai