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

Collection et Stream Java Discussion :

Héritage, généricité et collection


Sujet :

Collection et Stream Java

  1. #1
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2014
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 25
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2014
    Messages : 26
    Points : 12
    Points
    12
    Par défaut Héritage, généricité et collection
    Bonjour, je commence à apprendre java, mais voila que j'ai un problème, je vous explique:
    Code Java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class Garage 
    {
    	List<Voiture> list = new ArrayList<Voiture>();
    	public void add(List<? extends Voiture> voiture)
    	{
    		for(Voiture v : voiture)
    			list.add(v);
    		System.out.println("Contenu de votre garage:");
    		for(Voiture v : list)
    			System.out.println(v.toString());
    	}
    }
    Avec ce code, quand je vais dans la classe main et que je fais:
    Code Java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    List<VoitureSP> v2 = new ArrayList<VoitureSP>(); //VoitureSP hérite de Voiture
    		v2.add(new VoitureSP());
    		v2.add(new VoitureSP(12.0f));
     
    		Garage garage = new Garage();
    		garage.add(v2);
    cela fonctionne, mais si dans la fonction add du garage je remplace:
    Code Java : Sélectionner tout - Visualiser dans une fenêtre à part
    public void add(List<? extends Voiture> voiture)
    par
    Code Java : Sélectionner tout - Visualiser dans une fenêtre à part
    public void add(List<Voiture> voiture)
    , je ne peux plus ajouter une classe qui hérite de voiture, alors que plus haut dans la classe garage, j'ai bien une liste de Voiture qui peut bien contenir des Voiture plus des classes qui y héritent, je ne comprend pas pourquoi.
    Si je n'ai pas été assez clair, dites-le moi j'essayerai d'être plus précis, Merci

  2. #2
    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,


    C'est normal le polymorphisme ne peut pas fonctionner sur le typeage Generics.
    Ainsi, même si VoitureSP étend la classe Voiture, une List<VoitureSP> n'étend pas de List<Voiture> et ne peut donc pas y être affecté.

    Pourquoi ?
    Simplement parce que cela modifierait les contraintes du type paramétré.
    En effet le code suivant est tout à fait légal et typesafe :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    List<Voiture> list = ...
     
    list.add(new Voiture()); // OK
    list.add(new VoitureSP()); // OK
    En effet une List<Voiture> peut tout à fait contenir des objets de type Voiture ou VoitureSP.

    Maintenant si "list" pouvait représenter en réalité une List<VoitureSP> cela voudrait dire qu'avec ce code on y pourrait rajouter une Voiture, ce qui serait incohérent.

    Pire tu pourrais même faire cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    List<Voiture> voitures = new ArrayList<Voiture>();
    List<Object> objects = voitures; // ceci produit une erreur de compilation
     
    objects .add(new Date()); // OK... mais on met une Date dans une liste de Voiture !!!
    Bref cela casserait toute la sécurité du typeage !



    C'est toutefois très contraignant car cela force un typeage très fort, et c'est la raison d'être de la covariance/contravariance.

    La covariance permet d'utiliser un type de base pour effectuer des traitements dur un objet Generics.
    C'est exactement ce qui est fait dans List<? extends Voiture>.
    Cela signifie que l'on ne connait pas précisément le type du paramétrage Generics, mais qu'on sait qu'il s'agit soit de "Voiture" soit d'un type qui en hérite, et l'affectation devient possible :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    List<Voiture> voitures = new ArrayList<Voiture>();
    List<? extends Voiture> list = voitures; // OK
     
    List<VoitureSP> voituresSP = new ArrayList<VoitureSP>();
    List<? extends Voiture> list = voituresSP ; // OK
    Toutefois cela limite l'utilisation de certaines méthodes.
    En effet comme on ne connait pas précisément le type Generics, on ne peut pas utiliser les méthodes qui l'utilisent en paramètres.
    Par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    List<? extends Voiture> list = ...
     
    Voiture v = list.get(0); // OK
    Iterator<? extends Voiture> iterator = list.iterator(); // OK
     
    list.put(new Voiture()); // ERREUR de compilation




    De même la contravariance représente exactement l'inverse : un type paramétré dont on ne connait pas le type exact, si ce n'est que c'est un parent :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    // Une liste qui peut contenir des voitures, cela peut être :
    List<? super Voiture> list = new ArrayList<Voiture>();
    List<? super Voiture> list = new ArrayList<Object>();
    (toutefois son usage est plus restreint).



    a++

  3. #3
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2014
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 25
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2014
    Messages : 26
    Points : 12
    Points
    12
    Par défaut
    Ah super je comprend bien mieux, tu m'as éclairci beaucoup de chose de je ne comprenais pas. Toutefois je n'ai quand même pas compris quelque chose:
    Code Java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    List<VoitureSP> voituresSP = new ArrayList<VoitureSP>();
    List<? extends Voiture> list = voituresSP ; // OK
    Dans ce cas, on pourrais ajouter des Voiture dans la liste "list", ce qui en ajouterai par référence à la liste "voitureSP" ce qui ne serait pas cohérent, et par ce fait, c'est pour ça que "list" est bloquée en écriture à cause du "? extends Voiture" ?

  4. #4
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 552
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 552
    Points : 21 608
    Points
    21 608
    Par défaut
    En gros, oui.

    Mais ce n'est pas tellement une question de bloquer en écriture. Tu dis "on pourrais ajouter des Voiture la liste list." Bah non, on pourrait pas, c'est pas une List<Voiture> ou une List<Object> ou quoi que ce soit auquel on peut mettre des Voiture dedans, c'est une List<? extends Voiture>.

    List<? extends voiture> signifie en gros "List dont on ne sait pas ce qu'elle contient, mais on sait que ça étend Voiture." Comme on ne sait pas ce qu'elle contient, on ne sait pas ce qu'on a le droit ou pas le droit d'aller mettre dedans. Et c'est pour ça qu'on ne peut donc pas y mettre quoi que ce soit, l'effet "bloqué en écriture." Ce n'est pas une question de lecture/écriture, c'est une question que les méthodes à appeler prennent un paramètre, et qu'on ne sait pas quel est le type de ce paramètre, donc on ne peut pas les appeler*. Par contre on peut parfaitement appeler les méthodes qui enlèvent des éléments, puisqu'elles n'ont pas de paramètre de ce genre.

    * En fait on peut les appeler à condition que les paramètres en question, soient le littéral null. En effet, ce littéral est assignable à tous les types objets, et donc toujours acceptable même quand on ne connaît pas le type. Et donc, techniquement, la List<? extends Voiture> peut se faire ajouter des trucs. Des pointeurs null. C'est une très mauvaise pratique mais ça marche.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  5. #5
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2014
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 25
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2014
    Messages : 26
    Points : 12
    Points
    12
    Par défaut
    Okay et bien je vous remercie j'ai enfin a peu près capté, même si c'est quand même assez galère , Merci beaucoup!

Discussions similaires

  1. Héritage, Généricité, Cast?!
    Par aroussi_sanaa dans le forum Général Java
    Réponses: 1
    Dernier message: 04/05/2009, 11h10
  2. Collections et héritage de fiche
    Par Aka Guymelef dans le forum Composants VCL
    Réponses: 3
    Dernier message: 26/11/2008, 16h51
  3. Généricité et héritage
    Par TiteMarie dans le forum Langage
    Réponses: 3
    Dernier message: 27/05/2008, 12h17
  4. Collection et héritage
    Par BigNic dans le forum C#
    Réponses: 7
    Dernier message: 25/01/2008, 16h17
  5. Héritage et Iterateur de Collection
    Par onur dans le forum C++
    Réponses: 6
    Dernier message: 12/04/2006, 00h05

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