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

avec Java Discussion :

Problème de cast


Sujet :

avec Java

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Mars 2008
    Messages
    227
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2008
    Messages : 227
    Points : 77
    Points
    77
    Par défaut Problème de cast
    Bonjour à tous.
    Pour simplifier, voici mon problème:
    J'ai une classe Animal que je ne peux pas modifier, avec une instance "ani".
    Je veux ajouter des propriétés à cette classe:
    je la dérive en une classe Oiseau qui a la propriété "chante" en plus.
    Le but est de créer une instance "ois" de Oiseau qui récupère les propriété de ani (sans avoir à les dupliquer) et qui ajoute le booléen chante:
    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
     
    public class Animal {
    	int age;
    	public Animal(int age) {
    		this.age=age;
    	}
    }
     
    public class Oiseau extends Animal {
    boolean chante=false;
     
    	public Oiseau(int age,boolean ch) {
    		super(age);
    		chante=ch;
    	}
    }
     
    public class Essai {
    	public static void main(String[] args) {
    		Animal ani=new Animal(5);
    		Oiseau ois=(Oiseau) ani;
                              ois.chante=true;
    	}
    }
    Je n'ai pas d'erreur à la compilation mais une à l'exécution:
    "Animal cannot be cast to Oiseau"
    Pourtant je trouve normal de pouvoir caster ani en Oiseau pour pouvoir faire pointer ois dessus, non?

  2. #2
    Membre éprouvé
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 764
    Points : 909
    Points
    909
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Animal ani = new Animal(5);
    Oiseau ois = (Oiseau)ani;
    A la compilation le cast ne provoque pas d'erreur car théoriquement une instance de Animal pourrait être un Oiseau.
    A l'exécution il provoque une erreur parce que ce n'est pas le cas : tu as créé une nouvelle instance de Animal qui n'est pas un Oiseau...


    Le cast ne fonctionnera que si l'instance castée est effectivement un Oiseau :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Animal ani = new Oiseau(5, true);
    Oiseau ois = (Oiseau)ani;

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Mars 2008
    Messages
    227
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2008
    Messages : 227
    Points : 77
    Points
    77
    Par défaut
    OK mais le problème c'est que l'instance ani est déjà créée dans mon programme et je ne peux donc pas utiliser le constructeur Oiseau pour la définir.
    Mon but est de créer une instance ois de la classe Oiseau qui récupère toutes les propriétés de ani sans avoir à les dupliquer.
    Il y a bien un moyen de le faire?

  4. #4
    Membre éprouvé
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 764
    Points : 909
    Points
    909
    Par défaut
    Citation Envoyé par JCD21 Voir le message
    Mon but est de créer une instance ois de la classe Oiseau qui récupère toutes les propriétés de ani sans avoir à les dupliquer.
    Dans ce cas, il va falloir écrire un constructeur de Oiseau qui prend en paramètre une instance de Animal et recopie les propriétés de cette instance.
    Je ne sais pas ce que tu entends exactement par "sans avoir à les dupliquer" mais pour créer un Oiseau à partir d'un Animal, il faut créer une nouvelle instance, et donc il faut remplir à nouveau toutes les propriétés
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    // constructeur
    public Oiseau(Animal ani) {
       this.age = ani.age; // on copie les propriétés de l'Animal...
    }
     
    // utilisation
    Animal ani = new Animal(5);
    Oiseau ois = new Oiseau(ani);

  5. #5
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    ou alors utiliser un wrapper, dans ce cas, au lieu de dupliquer les propriétés, tu va devoir réécrire toutes les méthodes de animal:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class Oiseau extends Animal{
      private Animal reference;
      public Oiseau(Animal animal, boolean chante){
         super(0);
         this.reference=animal;
         this.chante=chante;
      }
      public int getAge(){return reference.getAge();}
      public void setAge(int age) {reference.setAge();}
      private boolean chante;
      public boolean isChante(){return chante;}
      public void setChante(boolean change) {this.chante=chante;}
    }
    Bien sur ca ne marche que pour des propriétés (getters / setters) pas pour des champs accédé directement.

  6. #6
    Membre éprouvé
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 764
    Points : 909
    Points
    909
    Par défaut
    Cette question me rappelait quelque chose, et effectivement j'ai retrouvé une ancienne discussion avec le même problème : http://www.developpez.net/forums/d74...nitialisation/

    Pour récapituler :
    Tu ne peux pas "transformer" un Animal en Oiseau, pour obtenir une instance d'Oiseau il faut forcément passer par un constructeur de la classe Oiseau.
    Et malheureusement, la copie des propriétés de ton instance d'Animal vers la nouvelle instance d'Oiseau ne peut pas se faire automatiquement, il faut la coder toi-même :
    - soit dans le constructeur comme suggéré dans mon message précédent
    - soit en "wrappant" l'instance d'Animal à l'intérieur de la classe Oiseau comme suggéré par tchize_

    L'avantage du wrapping, c'est que du côté constructeur c'est beaucoup plus simple (on référence l'instance d'Animal en une ligne au lieu de recopier chaque propriété).
    Le désavantage c'est qu'il faut ré-implémenter toutes les méthodes de Animal pour utiliser cette instance wrappée... ce qui peut au final être plus coûteux en nombre de lignes de code que d'effectuer des copies dans un constructeur. On n'y gagne donc pas forcément, au contraire.
    De plus c'est plutôt tordu d'un point de vue modélisation : un Oiseau n'est pas vraiment censé contenir un Animal. Et ça peut poser des problèmes si par la suite on oublie cette particularité et qu'on tente d'utiliser directement les champs de la classe Animal sans passer par l'instance wrappée ni par les getters redéfinis spécialement pour utiliser l'instance wrappée...



    EDIT : un autre argument en faveur du wrapping
    Si la classe Animal possède des propriétés private, auxquelles tu ne pourras pas avoir accès depuis la classe Oiseau, le wrapping t'assure de vraiment reprendre tout l'état interne de ton instance d'Animal.

    Je re-récapitule :
    - si tu as accès à toutes les propriétés internes de la classe Animal, le plus simple est de les recopier dans un constructeur de la classe Oiseau : une fois cette copie effectuée tu n'as plus d'autres souci à te faire
    - sinon, le wrapping de l'instance d'Animal à l'intérieur de la nouvelle instance d'Oiseau est la meilleure façon de s'assurer que toutes les propriétés de l'Animal (même celles non accessibles du fait de leur caractère privé) soient conservées, mais alors il faudra ensuite bien redéfinir toutes les méthodes de la classe Animal dans la classe Oiseau, de façon à les faire pointer vers l'instance wrappée, et faire attention à toujours utiliser les getters redéfinis pour accéder aux champs de la classe Animal : c'est une solution plus complexe et avec d'avantage de risque d'erreurs

  7. #7
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Citation Envoyé par Astartee Voir le message
    Le désavantage c'est qu'il faut ré-implémenter toutes les méthodes de Animal pour utiliser cette instance wrappée... ce qui peut au final être plus coûteux en nombre de lignes de code que d'effectuer des copies dans un constructeur.
    Sauf que pour ca, un bon IDE va coder toutes les méthodes pour toi en 2 secondes (sous eclipse, sélectionner l'attribut animal, -> source -> generate -> generate delegate methods)

    on tente d'utiliser directement les champs de la classe Animal sans passer par l'instance wrappée ni par les getters redéfinis spécialement pour utiliser l'instance wrappée...
    Encore une bonne raison pour toujours passer par des getters / setters à mon avis

  8. #8
    Membre régulier
    Profil pro
    Inscrit en
    Mars 2008
    Messages
    227
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2008
    Messages : 227
    Points : 77
    Points
    77
    Par défaut
    Je crois finalement que je vais utiliser la méthode du constructeur dans mon cas plutôt que le wrapper.
    En tout cas, merci pour vos réponses si complètes

Discussions similaires

  1. [CASTS]problème de cast de Time
    Par DeVoN dans le forum Langage
    Réponses: 7
    Dernier message: 22/02/2006, 17h24
  2. [JDBC Driver][JSTL] Problème de cast de données
    Par GyLes dans le forum PostgreSQL
    Réponses: 1
    Dernier message: 27/09/2005, 10h00
  3. problème de cast!
    Par LaseLiep dans le forum Langage
    Réponses: 3
    Dernier message: 03/06/2005, 09h30
  4. Problème de cast/serialization/externalization ?
    Par Linlin dans le forum CORBA
    Réponses: 1
    Dernier message: 06/12/2004, 16h46
  5. [C#] Problème de casting de @IDENTITY
    Par bilb0t dans le forum Accès aux données
    Réponses: 7
    Dernier message: 03/09/2004, 09h42

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