Maison  >  Article  >  Java  >  Pourquoi un List> autorise-t-il différents types de listes imbriquées ?

Pourquoi un List> autorise-t-il différents types de listes imbriquées ?

Patricia Arquette
Patricia Arquetteoriginal
2024-11-18 21:38:02952parcourir

Why Does a List<List<?>> Autoriser différents types de listes imbriquées ? 
> 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 . Cependant, la variante suivante ne compile pas :

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 🎜>

Le compilateur semble faire son travail, mais la confusion persiste avec la variation suivante :
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> ; mdr et une liste List ?
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 liste> représente une liste dont les éléments sont des listes de n'importe quel type, pas spécifiquement du même type. Cela signifie que le code suivant est légal :
A 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!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn