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 avec le polymorphisme


Sujet :

avec Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Developper
    Inscrit en
    Juin 2008
    Messages
    55
    Détails du profil
    Informations personnelles :
    Localisation : France, Vienne (Poitou Charente)

    Informations professionnelles :
    Activité : Developper

    Informations forums :
    Inscription : Juin 2008
    Messages : 55
    Par défaut Problème avec le polymorphisme
    Bonjour,

    je croyais avoir compris le polymorphisme (enfin pas toutes les arcanes, mais l'idée générale quoi), mais l'exemple suivant me pose problème :
    2 classes :
    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
    class A
    {
    	int f(A a)
    	{
    		return 1;
    	}
    }
     
    class B extends A
    {
    	int f(A a)
    	{
    		return 2;
    	}
     
    	int f(B b)
    	{
    		return 3;
    	}
    }
    le main :

    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
     
        public static void main(String[] args) {
            A a = new A();
            A ab = new B();
            B b = new B();
     
            // Partie a
            System.out.println( a.getClass() );
            System.out.println( a.f(a) );
            System.out.println( a.f(ab) );
            System.out.println( a.f(b) );
            System.out.println("");
            // Partie ab
            System.out.println( ab.getClass() );
            System.out.println( ab.f(a) );
            System.out.println( ab.f(ab) );
            System.out.println( ab.f(b) );
            System.out.println("");
            // Partie b
            System.out.println( ab.getClass() );
            System.out.println( b.f(a) );
            System.out.println( b.f(ab) );
            System.out.println( b.f(b) );
            System.out.println("");
     
        }
    et le résultat :

    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
     
    class javaapplication1.A
    1
    1
    1
     
    class javaapplication1.B
    2
    2
    2
     
    class javaapplication1.B
    2
    2
    3
    Le 1er lot, OK, a est une classe A donc f renvoie 1. Mais sur le second, j'ai du mal, notamment : System.out.println( ab.f(ab) )
    comme on a un 2, ça veux dire qu'on considère que la méthode f est celle de la classe B, donc ab. est un objet B, mais comme on a 2 ça veux dire qu'on prend la méthode int f(A a) donc ça veux dire que ab passé en paramètre est une classe A...
    j'aurais compris qu'on ai 1 : ab est A ou qu'on ait 3 : ab est B... mais qu'on ait 2, là, je comprend pas. Je sais que le polymorphisme c'est justement que ab est B et est A... mais que dans la même expression ab soit A et B, j'ai du mal

    Quelqu'un aurait la gentillesse de m'expliquer ?

    Merci

    harf
    geff

  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,



    Déjà tu as deux concepts différents :
    • Le polymorphisme par dérivation (ou héritage), que l'on appelle généralement redéfinition (ou overrides en anglais).

      Cela consiste à créer dans une classe fille une méthode avec la même signature, qui contiendrait un code différent. Dans ton exemple la méthode f(A) de la classe B est une redéfinition de la méthode f(A) de la classe A. Ces deux méthodes ont un lien de parenté entre elles (c'est très important on le verra plus bas).

    • Le polymorphisme ad hoc, que l'on appelle généralement surcharge (ou overload en anglais).

      Cela consiste à créer dans une même classe une méthode avec le même nom mais des paramètres différents (en type ou en nombre). En fait malgré leurs noms identiques, il faut considérer les méthodes comme étant totalement différentes : il n'y a aucun lien entre elle...





    Ensuite il faut comprendre que par défaut en Java les méthodes sont virtuelle. C'est à dire que la méthode qui sera réellement exécuté dépendra du type réel à l'exécution, selon la méthode choisi à la compilation.


    Cela se fait donc en deux étapes.

    C'est à la compilation que le choix de la méthode a appellé est déterminé, selon le type déclaré de la variable :
    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
            // Partie a
            System.out.println( a.getClass() );	// a est déclaré en type A, qui ne possède qu'une méthode f(A)
            System.out.println( a.f(a) );		// => A.f(A)
            System.out.println( a.f(ab) );		// => A.f(A)
            System.out.println( a.f(b) );		// => A.f(A)
            System.out.println("");
            // Partie ab
            System.out.println( ab.getClass() );	// ab est déclaré en type A, qui ne possède qu'une méthode f(A)
            System.out.println( ab.f(a) );		// => A.f(A)
            System.out.println( ab.f(ab) );		// => A.f(A)
            System.out.println( ab.f(b) );		// => A.f(A)
            System.out.println("");
            // Partie b
            System.out.println( ab.getClass() );	// b est déclaré en type B, qui possède une méthode f(A) et f(B)
            System.out.println( b.f(a) );		// => B.f(A)
            System.out.println( b.f(ab) );		// => B.f(A) car ab est déclaré comme un type A
            System.out.println( b.f(b) );		// => B.f(B)
            System.out.println("");
    Cela correspond peut être un peu plus à ce que tu attendais. Mais il ne s'agit ici que de la compilation. A l'exécution la notion de méthode virtuelle rentre en jeu : pour chaque méthode virtuelle, la machine virtuelle va vérifier le type réel de l'instance pour éventuellement appeller une redéfinition de méthode (c'est là que rentre en jeu le lien de parenté) :

    En fait avant d'exécuter une méthode, la JVM va vérifier le type réel de l'objet afin de vérifier s'il existe une redéfinition de la méthode pour appeller cette méthode là plutôt que la méthode parente.

    Donc lorsque tu exécutes la méthode A.f(A) sur un objet de type réel B, la JVM va voir que la méthode est redéfini et va donc exécuter le code redéfini.

    Sur les références "a" et "b" il n'y a pas de modification car le type déclaré est le même que le type réel, mais sur la référence "ab" tu as une différence donc la JVM joue son rôle (elle recherche la redéfinition de méthode) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    ab.f(a); // Appel de A.f(A) sur "ab"
    // => La JVM vérifie le type réel de "ab" qui est "B"
    // => Le type B a redéfini la méthode f(A)
    // => La JVM exécute le code de la méthode B.f(A)


    Je ne sais pas si c'est clair ??

    a++

  3. #3
    Membre confirmé
    Profil pro
    Developper
    Inscrit en
    Juin 2008
    Messages
    55
    Détails du profil
    Informations personnelles :
    Localisation : France, Vienne (Poitou Charente)

    Informations professionnelles :
    Activité : Developper

    Informations forums :
    Inscription : Juin 2008
    Messages : 55
    Par défaut
    Merci beaucoup pour ta réponse argumentée, mais je bute toujours sur ab.f(ab) qui renvoie 2

    OK la JVM trouve que ab est bien de type B (jusque là, je comprend)
    or dans la classe B, j'ai "int f(B b) { return 3; }" donc ab.f(ab) revient, pour moi à "objet_de_classe_B.f(objet_de_classe_B) donc 3... Or, en fait c'est égale à 2, donc ça se comporte comme objet_de_classe_B.f(objet_de_classe_A)

    j'en profite pour une nouvelle question parallèle : c'est quoi la 3ème forme de polymorphisme ?

    merci encore

  4. #4
    Membre éclairé
    Homme Profil pro
    Développeur full-stack
    Inscrit en
    Mai 2002
    Messages
    46
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur full-stack

    Informations forums :
    Inscription : Mai 2002
    Messages : 46
    Par défaut
    Le cas difficile:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    A ab = new B();
    System.out.println( ab.f(ab) );
    A l'exécution, il va falloir trouver la méthode à appeler:

    -d'abord quelle classe ?
    dans l'expression "ab." on détermine le type de l'objet ab: class B

    - ensuite quelle méthode ?
    dans l'expression "ab.f(ab)"
    pour ça il faut déterminer le type de la référence passée en paramètre (et non le type de l'objet) càd A
    (ceci est vrai en java mais pas dans tous les langages objet)

    -> donc on apelle "B.f(A a)" (return 2)

    pas de problème avec type d'objet / type d'une référence ?

  5. #5
    Membre éclairé
    Homme Profil pro
    Développeur full-stack
    Inscrit en
    Mai 2002
    Messages
    46
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur full-stack

    Informations forums :
    Inscription : Mai 2002
    Messages : 46
    Par défaut
    euuh, je viens de tester, je suis plus trop sûr de ce que j'avance
    ça m'intrigue, je continu de tester

  6. #6
    Membre éclairé
    Homme Profil pro
    Développeur full-stack
    Inscrit en
    Mai 2002
    Messages
    46
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur full-stack

    Informations forums :
    Inscription : Mai 2002
    Messages : 46
    Par défaut
    ok, j'ai oublié une étape:

    au début de la recherche de méthode, il faut restreindre la liste des méthodes possibles en gardant que celles qui sont visibles.

    donc dans notre cas:
    dans l'expression "ab." la référence ab est de type A donc ne seront visible que les méthodes de A (la méthode f(B) ne pourra pas être exécutée)

    c'est pas terrible comme explication, mais c'est pas tous les jour qu'on voit des cas dans ce genre ^^

Discussions similaires

  1. Problème avec le polymorphisme
    Par Vitis_Alba dans le forum C++
    Réponses: 14
    Dernier message: 15/01/2007, 16h41
  2. VC++ Direct3D8, problème avec LPD3DXFONT et LPD3DTEXTURE8
    Par Magus (Dave) dans le forum DirectX
    Réponses: 3
    Dernier message: 03/08/2002, 11h10
  3. Problème avec le type 'Corba::Any_out'
    Par Steven dans le forum CORBA
    Réponses: 2
    Dernier message: 14/07/2002, 18h48
  4. Problème avec la mémoire virtuelle
    Par Anonymous dans le forum CORBA
    Réponses: 13
    Dernier message: 16/04/2002, 16h10

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