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 :

[Generics/Tableaux] Problèmes de succession


Sujet :

Langage Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Par défaut [Generics/Tableaux] Problèmes de succession
    Suite à l'article de Romain Guy sur les problèmes de succession au niveau des Generics en java, Java 5.0 interdit tout simplement de faire ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    List<Double> nombres = new ArrayList<Double>();
    List<Object> objets = nombres;
    Et les explications données sont un bon argument...

    Cependant, je me pose une question... On rencontre exactement le même problème avec les tableaux qu'avec les types paramétrés... Pourtant, il est possible de faire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    String[] str = new String[1];
    Object[] obj = str;
    obj[0] = 5;
    ou même directement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Object[] obj = new String[1];
    obj[0] = 5;
    Cela compile très bien.

    Par contre, à l'exécution, la dernière ligne lève une java.lang.ArrayStoreException.

    Pourquoi donc n'avoir pas utilisé le même comportement pour les tableaux que pour les generics? Soit interdire dans les 2 cas, soit autoriser dans les 2 cas...

    EDIT: Dans le même genre, pourquoi l'auto-(un)boxing autorise Integer <-> int mais pas Integer[] <-> int[] ?

    Merci de votre réponse...

  2. #2
    Expert éminent
    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
    Billets dans le blog
    1
    Par défaut
    Salut,


    Les tableaux ont un héritage particulier, qui "respectent" un peu celui des classes. Par exemple, comme on a l'héritage suivant :
    • Object <- Number <- Integer
    On a lé même héritage avec les tableaux :
    • Object[] <- Number[] <- Integer[]
    C'est un des principes des tableaux en Java, et lorsqu'on affecte un référence à un indice d'un tableau, le type du tableau est vérifié et génère une ArrayStoreException en cas de problème. Cette vérification des types est effectué à l'exécution...

    Ce mécanisme est le même depuis Java 1.0.




    Alors pourquoi ne pas avoir utilisée le même mécanisme dans les Generics ?

    Tout simplement parce que la vérification des types est effectué à la compilation, et qu'ils sont perdus à l'exécution.

    Ainsi le code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    List<Double> nombres = new ArrayList<Double>();
    List<Object> objets = nombres; // Erreur de compilation
    objets.add( new String("hello") );
    Double d = nombres.get(0);
    La seconde ligne provoque une erreur.
    Or si cette dernière était authorisé, et puisque les types générics sont perdus à l'exécution, cela reviendrait à avoir le code suivant non-typé :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    List nombres = new ArrayList();
    List objets = nombres;
    objets.add( new String("hello") ); // Ne provoque pas d'erreur
    Double d = (Double)nombres.get(0); // ClassCastException
    Le problème : la troisième ligne (le add()) devrait provoquer une exception puisqu'il est à la source de l'erreur. Or il n'en est rien, et l'erreur ne sera provoquer que sur la dernière ligne, alors qu'il s'agissait bien d'une List<Double>...


    Ainsi on se retrouve avec une Exception sur une ligne de code qui aurait dû être sécurisé par l'utilisation des Generics, et il peut être difficile de retrouver la ligne exacte de l'erreur (dans le cas où elle ne serait pas juste au dessus bien sûr).


    Et comme les Generics ont pour principal objectifs de proposer du code type-safe, c'est totalement incompatible...



    La solution est donné par Romain dans son article, il faut utiliser le meta ? pour indiquer qu'on souhaite utiliser les classe filles :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    List<Double> nombres = new ArrayList<Double>();
    List<? extends Object> objets = nombres; 
    objets.add( new String("hello") ); // Erreur de compilation
    Double d = nombres.get(0);
    Ainsi on peut utiliser une List d'objet, et on obtient une erreur de compilation sur le code incorrect (le add()) puisqu'on ne peut pas connaitre le type exact de la List...


    Il faut bien prendre en compte le fait suivant : Si les classes Générics compilent sans erreur ni warning, alors on ne devrait pas obtenir de ClassCastException à l'exécution.

    C'est une philosophie très différentes des tableaux qui peuvent provoquer un grand nombre d'exception du fait de leurs héritage...

    a++

  3. #3
    Membre éprouvé
    Avatar de mavina
    Homme Profil pro
    Développeur Java
    Inscrit en
    Octobre 2004
    Messages
    1 812
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : Chine

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2004
    Messages : 1 812
    Par défaut
    Salut,

    Le fait de faire List<Integer> garentie normalement que tous les objets de ta liste seront une instance de Integer. Il est donc logique qu'une référence sur List<Object> ne puisse pointer sur List<Integer>.

    Quant aux tableaux, tu ne paramètre pas ton tableau, tu lui dits juste que ton tableau contiendra des Object, et plus précisémment des String. Puis tu lui rentre une instance d'Object, qui en fait est une instance de Integer. Le problème vient (je pense) du fait que cette instance ne dérive pas de String (ou n'est pas une instance de String elle même). Tu ne respecte donc pas les regles de polymorphisme, une exception est levée. Le fait d'entrer un Object (Integer) dans ton tableau fait que ca compile, mais le fait que le tableau soit spécifié new String[] fait que l'exception est levée.

    Bien à toi

    Fred, qui espère ne pas se tromper

    P.S. : attends quand même l'avis d'un "pro" de ce genre de concepts

    edit : fichtre, owned

Discussions similaires

  1. [Tableaux] Problème avec array_multisort
    Par ecocentric dans le forum Langage
    Réponses: 5
    Dernier message: 27/09/2005, 14h56
  2. [Tableaux] Problème avec les boucles
    Par speed_man002 dans le forum Langage
    Réponses: 4
    Dernier message: 21/09/2005, 15h42
  3. [Tableaux] problème de concaténation
    Par ludovik dans le forum Langage
    Réponses: 3
    Dernier message: 13/09/2005, 13h24
  4. [Tableaux] problème avec while
    Par zimotep dans le forum Langage
    Réponses: 3
    Dernier message: 11/09/2005, 10h30
  5. [Tableaux] Problème avec Switch case
    Par philippef dans le forum Langage
    Réponses: 4
    Dernier message: 07/09/2005, 16h37

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