> Autoriser différents types de listes imbriquées ? " />
Plusieurs caractères génériques sur les méthodes génériques peuvent confondre le compilateur Java
Le problème :
Utilisation de plusieurs caractères génériques sur Les méthodes génériques peuvent prêter à confusion à la fois pour le compilateur Java et pour le programmeur. Considérons l'exemple suivant :
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! } }
Deux caractères génériques non liés peuvent être utilisés pour appeler doNothing avec un List
public class TwoListsOfUnknowns2 { static void doSomethingIllegal(List<?> list1, List<?> list2) { list1.addAll(list2); // DOES NOT COMPILE!!! } }
Ce comportement est attendu car list1 et list2 font référence à des types entièrement différents.
Une confusion survient avec le code suivant :
public class LOLUnknowns1 { static void probablyIllegal(List<List<?>> lol, List<?> list) { lol.add(list); // this compiles!! how come??? } }
Ce code se compile, mais devrait-il le faire ? Il est possible d'avoir une liste List> et une liste List
public class LOLUnknowns2 { static void rightfullyIllegal( List<List<? extends Number>> lol, List<?> list) { lol.add(list); // DOES NOT COMPILE! As expected!!! } }Ce code ne devrait-il pas être compilé car il peut impliquer une liste
public class LOLUnknowns3 { static void probablyIllegalAgain( List<List<? extends Number>> lol, List<? extends Number> list) { lol.add(list); // compiles fine!!! how come??? } }
Pour clarifier ces comportements, simplifions le code en LOLUnknowns1 et essayons d'invoquer probablementIllegal :
Même avec le même type pour les deux. caractères génériques, le code ne se compile pas. Cependant, un type nul pour le premier argument compile :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! } }La réponse :
La confusion vient d'une incompréhension de ce qu'est un caractère générique imbriqué, tel que List< ;Liste>>, signifie en fait. Java Generics est invariant, ce qui signifie que les relations entre les types ne s'appliquent pas aux instanciations génériques. Cela s'applique également aux listes imbriquées :
Par conséquent, une listeA 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>());En résumé
Le comportement du compilateur Java avec plusieurs caractères génériques génériques est déterminé par les règles de conversion de capture. Comprendre les limites de la capture de caractères génériques est crucial pour éviter toute confusion.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!