> 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! } }
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>());
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