IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Java Discussion :

Question de généricité et d'héritage


Sujet :

Langage Java

  1. #1
    Membre régulier Avatar de fatypunk
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    71
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2007
    Messages : 71
    Points : 74
    Points
    74
    Par défaut Question de généricité et d'héritage
    Résumé :
    On ne peut pas passer une Collection<List<Collection<String>>> à une méthode qui prend comme paramètre une Collection<Collection<Collection<String>>>.
    Pourquoi?
    Je constate que le code suivant ne passe pas :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    public class Test {
     
        public Test() {
            Collection<List<Collection<String>>> c = new ArrayList<List<Collection<String>>>();
     
            List<Collection<String>> c1 = new ArrayList<Collection<String>>();
            Collection<String> c2 = new ArrayList<String>();
            c2.add("test1");
            c2.add("test2");
            c1.add(c2);
     
            c2 = new ArrayList<String>();
            c2.add("test3");
            c1.add(c2);
            c.add(c1);
     
            c1 = new ArrayList<Collection<String>>();
            c2 = new ArrayList<String>();
            c2.add("test4");
            c1.add(c2);
            c.add(c1);       
     
            print(c);
        }
     
        private void print(Collection<Collection<Collection<String>>> c) {
     
            System.out.println("Résultat :");
     
            for(Collection<Collection<String>> c1 : c) {
                for (Collection<String> c2 : c1) {
                    for (String s : c2) {
                        System.out.println(s);
                    }
                }
            }
     
        }
     
    }
    il génère l'erreur de compilation suivant sur l'appel de print(c) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    /home/[*******]/devel/java/TestApplication/src/testapplication/Test.java:38:
    print(java.util.Collection<java.util.Collection<java.util.Collection<java.lang.String>>>)
    in testapplication.Test cannot be applied to
    (java.util.Collection<java.util.List<java.util.Collection<java.lang.String>>>)
    La question est pourquoi ? Une List est pourtant une Collection. Mais le compilateur ne semble pas apprécier l'utilisation d'une interface enfant dans le cas d'une généricité imbriquée.
    Développeur Java SE, Java EE (EJB3)
    IDE : Netbeans 6.5 / Serveur d'application : Glassfish v2.1 / OS : Ubuntu 8.10 Intrepid Ibex et CentOS 5
    Historique : GWBasic, Turbo Pascal (beaucoup), Visual Basic, C (un peu), C++ (beaucoup), Assembleur (6800 et x86 / un peu), Java, Smalltalk (un peu), Lisp (un peu), Prolog (un peu), PHP, Ruby (un peu), et retour à Java (beaucoup).

    Pas de questions techniques par MP s'il vous plait !

  2. #2
    Membre averti
    Profil pro
    Développeur Java
    Inscrit en
    Novembre 2007
    Messages
    301
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Novembre 2007
    Messages : 301
    Points : 368
    Points
    368
    Par défaut
    Cette question est discutée dans le didacticiel officiel sur les génériques dans le paragraphe 3 : "Generics and Subtyping".

    In general, if Foo is a subtype (subclass or subinterface) of Bar, and G is some generic type declaration, it is not the case that G<Foo> is a subtype of G<Bar>. This is probably the hardest thing you need to learn about generics, because it goes against our deeply held intuitions.
    EDIT: Je pense que tu pourrais garder ton code avec Collection en modifiant de la sorte <? extends Collection>. Je n'ai jamais testé par contre.

  3. #3
    Membre chevronné
    Avatar de Anthony.Desvernois
    Homme Profil pro
    Ingénieur sécurité & risque
    Inscrit en
    Juin 2007
    Messages
    1 489
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur sécurité & risque
    Secteur : Finance

    Informations forums :
    Inscription : Juin 2007
    Messages : 1 489
    Points : 2 244
    Points
    2 244
    Par défaut
    Salut,

    Tu peux utiliser cette définition pour print (generics, toussa):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    private <A extends Collection<String>, B extends Collection<A>, C extends Collection<B>> void print(C c) {
     
        System.out.println("Résultat :");
     
        for(B c1 : c) {
            for (A c2 : c1) {
                for (String s : c2) {
                    System.out.println(s);
                }
            }
        }
     
    }
    Have fun

    PS: Si besoin d'explication, n'hésites pas à demander
    "Voyager, c'est découvrir que tout le monde a tort", Aldous Huxley
    "Less is more" Ludwig Mies Van Der Rohe

    Risk & Security Mgmt

  4. #4
    Invité
    Invité(e)
    Par défaut
    salut

    J'approuve darkxan. Le truc c'est que
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    TypeGenerique<Object>
    n'est pas le surtype de tous les TypeGenerique, le surtype est :

  5. #5
    Membre régulier Avatar de fatypunk
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    71
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2007
    Messages : 71
    Points : 74
    Points
    74
    Par défaut
    Merci !! Je n'ai pas vraiment à résoudre ce problème actuellement, c'est juste pour mieux comprendre. Là j'ai une explication logique (plus que "on peut pas...").

    Les 2 solutions fonctionnent :

    Celle de Anthony.Desvernois (Netbeans crois qu'il y a une erreur mais il n'y en a pas).

    Celle-ci est ma préférée :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
        private void print(Collection<? extends Collection<? extends Collection<String>>> c) {
     
            System.out.println("Résultat :");
     
            for(Collection<? extends Collection<String>> c1 : c) {
                for (Collection<String> c2 : c1) {
                    for (String s : c2) {
                        System.out.println(s);
                    }
                }
            }    
        }
    Développeur Java SE, Java EE (EJB3)
    IDE : Netbeans 6.5 / Serveur d'application : Glassfish v2.1 / OS : Ubuntu 8.10 Intrepid Ibex et CentOS 5
    Historique : GWBasic, Turbo Pascal (beaucoup), Visual Basic, C (un peu), C++ (beaucoup), Assembleur (6800 et x86 / un peu), Java, Smalltalk (un peu), Lisp (un peu), Prolog (un peu), PHP, Ruby (un peu), et retour à Java (beaucoup).

    Pas de questions techniques par MP s'il vous plait !

  6. #6
    Membre chevronné
    Avatar de Anthony.Desvernois
    Homme Profil pro
    Ingénieur sécurité & risque
    Inscrit en
    Juin 2007
    Messages
    1 489
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur sécurité & risque
    Secteur : Finance

    Informations forums :
    Inscription : Juin 2007
    Messages : 1 489
    Points : 2 244
    Points
    2 244
    Par défaut
    Ben en fait c'est les mêmes, juste la syntaxe utilisée qui est différente
    N'oublis pas le tag résolu
    "Voyager, c'est découvrir que tout le monde a tort", Aldous Huxley
    "Less is more" Ludwig Mies Van Der Rohe

    Risk & Security Mgmt

  7. #7
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Salut,


    Comme cela a été dit, il n'y a pas d'héritage dans les types paramétré pour éviter des erreurs à l'exécution, contrairement à ce qui existe avec les tableaux.

    Par exemple, avec les tableaux on peut faire ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Number[] numbers = new Integer[5];
    numbers[0] = new Double(0.0);
    On crée un tableau d'Integer que l'on déclare comme un tableau de Number (c'est autorisé grace à l'héritage particulier des tableaux), puis on place un Double dans ce tableau de Number. Au niveau de la compilation toutes ces opérations sont parfaitement légales et cela compilera sans erreur, mais à l'exécution on aura une ArrayStoreException puisqu'on essaye de mettre un Double dans un tableau d'Integer.



    L'objectif des Generics étant de détecter ce types d'erreurs à la compilation, ce type d'héritage est interdit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    List<Number> list = new ArrayList<Integer>(); // Erreur de compilation !
    A la place on peut utiliser les wilcards ? extends et ? super :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    List<? extends Number> list = new ArrayList<Integer>();
    On a une liste d'objet qui hérite de Number, mais on ne connait pas le type précis, du coup certaines méthodes ne peuvent pas être utilisé :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    List<? extends Number> list = new ArrayList<Integer>();
    Number n = list.get(0); // OK : le type de retour est un type fils
     
    list.add(new Double(0.0)); // ERREUR de compilation : on ne connait pas le type précis de la liste, on ne peut donc pas ajouter d'élément
    Grosso-modo le ? extends permet de n'utiliser que les méthodes qui renvoi un objet paramétré (en utilisant le type de base), mais pas celle qui en utilise un en paramètre (puisqu'on ignore le type réel).

    Par exemple cela permet de lire les éléments d'une collection :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    public void printAll(Collection<?> c) { // <?> == <? extends Object>
        for (Object o : c) {
            System.out.println(o);
        }
    }

    Le ? super permet l'inverse, mais les cas d'utilisation sont plus rare :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    List<? super Number> list = new ArrayList<Number>();
     
    list.add(new Double(0.0); // On peut ajouter des éléments
     
    // Mais pas les lire :
    Number n = list.get(0); // ERREUR : on ne connait pas le type de retour


    a++

  8. #8
    Membre régulier Avatar de fatypunk
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    71
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2007
    Messages : 71
    Points : 74
    Points
    74
    Par défaut
    Citation Envoyé par Anthony.Desvernois Voir le message
    Ben en fait c'est les mêmes, juste la syntaxe utilisée qui est différente
    N'oublis pas le tag résolu
    Oui, mais c'est bien la syntaxe que je préfère !
    De plus mon IDE a de la peine avec l'autre...

    Merci adiGuba pour toutes ces précisions, là c'est vraiment résolu (cette fois je maîtrise bien les generics java) !!!

    Développeur Java SE, Java EE (EJB3)
    IDE : Netbeans 6.5 / Serveur d'application : Glassfish v2.1 / OS : Ubuntu 8.10 Intrepid Ibex et CentOS 5
    Historique : GWBasic, Turbo Pascal (beaucoup), Visual Basic, C (un peu), C++ (beaucoup), Assembleur (6800 et x86 / un peu), Java, Smalltalk (un peu), Lisp (un peu), Prolog (un peu), PHP, Ruby (un peu), et retour à Java (beaucoup).

    Pas de questions techniques par MP s'il vous plait !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [JPQL] Question sur une requête avec héritage
    Par saveriu dans le forum JPA
    Réponses: 1
    Dernier message: 21/08/2010, 08h54
  2. Question sur les notion d'héritages
    Par shinrei dans le forum Débuter
    Réponses: 6
    Dernier message: 25/07/2006, 14h59
  3. [Héritage] Question sur le polymorphisme
    Par nikhil dans le forum C++
    Réponses: 7
    Dernier message: 28/12/2005, 20h33
  4. Réponses: 2
    Dernier message: 04/12/2005, 21h10
  5. Question d'héritage : Overload ou reintroduce ?
    Par LadyWasky dans le forum Langage
    Réponses: 9
    Dernier message: 31/10/2005, 13h07

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo