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 :

Liaison dynamique


Sujet :

avec Java

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    84
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2011
    Messages : 84
    Points : 51
    Points
    51
    Par défaut Liaison dynamique
    Bonjour,

    je suis tombé sur cet exercice sur internet:

    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
    class A{
      void m(A a){
        System.out.println("m de A");
      }
      void n(A a){
        System.out.println("n de A");
      }
    }
     
     
    class B extends A{
      void m(A a){
        System.out.println("m de B");
      }
      void n(B b){
        System.out.println("n de B");
      }
      public static void main(String[] argv){
        A a = new B();
        B b = new B();
        a.m(b);
        a.n(b);
      }
    }
    Le main affiche
    m de B
    n de A
    mais je ne voie pas pq...D'après moi:
    a et b référencent des objets de type B.
    on appelle l'opération m(B) de la classe B qui n'existe pas pour un objet B en paramètre, mais un objet B est aussi un objet A, donc on appelle m(A) de la classe A qui affiche m de A
    La 2ème ligne me choque encore plus:
    on appelle a.n(b); avec a et b des références sur des objets de la classe B, donc on appelle n(B) de la classe B qui devrait normalement afficher:
    n de b
    ???
    Merci.

  2. #2
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Salut,

    La première chose à remarquer dans ce code, c'est que les méthodes ne font qu'afficher une chaîne de caractères fixe, qui ne dépend pas du paramètre.

    Ensuite, il y a 2 classes, A et B qui étend A. Dans A, on a 2 méthodes, m() et n() prenant en paramètre une instance de type A.

    Dans B, on :
    • définit la méthode m(A a), ce qui surcharge celle de A, donc la redéfinit (la remplace donc dans B, en quelque sorte)
    • définit une méthode n(B b), qui elle, a un argument qui n'est pas du même type que celui de la méthode n(A a) de A. Elle ne rédéfinit donc pas cette dernière : elle s'ajoute en fait (polymorphisme : on a 2 méthodes n() dans B, une qui prend un paramètre de type A et une qui prend un paramètre de type B. Le nom des paramètres n'est pas à prendre en compte.


    La méthode main() crée 2 instances, de classe B :
    • a de classe B, mais typé A (pour le compilateur, a est de type A, même si sa classe est B.
    • et b de classe B, typé B.

    Puis elle appelle les méthodes :
    • m(b) sur a ; le compilo cherche la méthode qui convient (compatible pour le type de la variable passée en paramètre) dans la classe A, donc m(A), puisque B étend A (elle est donc bien compatible), et l'appelle.
      Mais, c'est bien la méthode de la classe de l'instance qui est appelée, donc m(A) de B (la classe de a), c'est-à-dire la surcharge dans la classe B, qui affiche naturellement "m de B"
    • puis n(b) sur a, de type A ; le compilo cherche la méthode qui convient, et trouve n(A) dans le type A, puisque b est de type B et que B étend A (elle est bien compatible).
      Puis exécute cette méthode, dans la classe B, puisque b est de classe B.
      Mais cette méthode n'est pas surchargée (on l'a vu avant : la méthode n(B) ne surcharge pas n(A).
      Donc, le code exécuté est celui de la méthode n() de la classe A, qui affiche naturellement "n de A"



    C'est un exercice piège pour faire comprendre l'importance des types des variables et les classes des instances.

    Peut être que ce petit sample de permettra de comprendre plus facilement :

    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 DemoEquals {
     
    	private int valeur;
     
    	public DemoEquals() {
    		valeur = 0;
    	}
     
    	public boolean equals(DemoEquals obj) {
    		return obj.valeur==valeur;
    	}
    	/*public boolean equals(Object obj) {
    		if ( obj instanceof DemoEquals ) {
    			return equals((DemoEquals)obj);
    		}
    		return super.equals(obj);
    	}*/
     
    	public static class DemoEquals2 extends DemoEquals {
     
     
     
    	}
     
    	public static void main(String[] args) {
     
    		DemoEquals2 obj1 = new DemoEquals2();
    		DemoEquals2 obj2 = new DemoEquals2();
     
    		System.out.println(obj1.equals(obj2)); // affiche true, parce que finalement c'est equals(DemoEquals) qui est appellé
    		Object obj2typeObject = obj2;
    		System.out.println(obj1.equals(obj2typeObject)); // affiche false, parce que c'est equals(Object) qui est appelé
    		Object obj1typeObject = obj1;
    		System.out.println(obj1typeObject .equals(obj2)); // affiche false, parce que c'est equals(Object) qui est appelé
    System.out.println(obj1typeObject .equals(obj2typeObject)); // affiche false, parce que c'est equals(Object) qui est appelé
    		// décommente la méthode equals(Object) et réexecute : tu verras que l'affichage est true, puis true, puis true, et, enfin, true
     
    	}
     
    }

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    84
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2011
    Messages : 84
    Points : 51
    Points
    51
    Par défaut
    j'y réfléchis ^^

  4. #4
    Membre du Club
    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    84
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2011
    Messages : 84
    Points : 51
    Points
    51
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public static void main(String[] args) {
     
    		DemoEquals2 obj1 = new DemoEquals2();
    		DemoEquals2 obj2 = new DemoEquals2();
    		System.out.println(obj1.equals(obj2)); // affiche true, parce que finalement c'est equals(DemoEquals) qui est appellé
    		Object obj2typeObject = obj2;
    		System.out.println(obj1.equals(obj2typeObject)); // affiche false, parce que c'est equals(Object) qui est appelé
    		Object obj1typeObject = obj1;
    		System.out.println(obj1typeObject .equals(obj2)); // affiche false, parce que c'est equals(Object) qui est appelé
    		System.out.println(obj1typeObject .equals(obj2typeObject)); // affiche false, parce que c'est equals(Object) qui est appelé
    		// décommente la méthode equals(Object) et réexecute : tu verras que l'affichage est true, puis true, puis true, et, enfin, true
     
    	}
    A la ligne 5: equals(DemoEquals) est appelé et non pas equals(DemoEquals2) car on appelle les méthodes qui sont définies dans l'arbre d'héritage le plus près de la classe réelle de l'objet à savoir ici DemoEquals2 pour obj1. Comme equals n'est pas définie dans DemoEquals2, c'est celle de la classe parente (la plus proche) qui est appelée à savoir equals(DemoEquals). Le raisonnement est bon ?

    A la ligne 9: pourquoi est-ce equals(Object) qui est appelée et non pas equals(DemoEquals) ? (en suivant mon raisonnement ci-dessus) ?

  5. #5
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Il faut bien distinguer la détermination de la méthode à appeler, et l'exécution.

    Le compilateur détermine la méthode à appeler par rapport aux informations qu'il connait : le type de la variable sur laquelle la méthode est appelée, et les méthodes qui sont présentes dans ce type. Puis les types des variables des paramètres.

    En ligne 5, le type de obj1 est DemoEquals, donc les méthodes trouvées sont :

    • equals(DemoEquals obj)
    • equals(Object obj) héritée de Object


    Le type du paramètre obj2 est DemoEquals, donc c'est la première méthode qui va être sélectionnée, parce qu'elle matche au mieux.

    En ligne 9, le type de obj1typeObject est Object, donc les méthodes trouvées sont :

    • equals(Object obj) héritée de Object


    Donc, la seule qui matche le type de obj2, c'est equals(Object) (puisque c'est la seule trouvée).

    Ensuite, lors de l'exécution, c'est la méthode dans la classe qui est exécutée. Comme equals(Object) n'est pas redéfinie dans DemoEquals, c'est la méthode de la superclasse qui est exécutée, qui compare les instances, qui sont différentes, donc le résultat est false.

    Si tu décommentes la méthode equals dans DemoEquals, ça ne change rien au niveau de la sélection de la méthode, mais à l'exécution, on exécute la méthode redéfinie dans DemoEquals, qui délègue la comparaison à la méthode equals(DemoEquals) si l'instance est de classe DemoEquals méthode qui compare bien les valeurs de la variable interne valeur, qui sont égales, d'où le résultat vrai.

  6. #6
    Membre du Club
    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    84
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2011
    Messages : 84
    Points : 51
    Points
    51
    Par défaut
    Ensuite, lors de l'exécution, c'est la méthode dans la classe qui est exécutée. Comme equals(Object) n'est pas redéfinie dans DemoEquals, c'est la méthode de la superclasse qui est exécutée, qui compare les instances, qui sont différentes, donc le résultat est false.
    ? Je ne comprends pas. Et puis pourquoi cela affiche false alors que obj2 et obj1typeobjet sont tous les deux de type Object ?

  7. #7
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    La variable obj1typeobjet est de type Object et la variable obj2 de type DemoEquals2, mais la classe des objets référencés par ces variables est DemoEquals2.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Type variable = new Classe();
    Type utilisé par le compilateur, quand tu fais, pour déterminer methode() :
    Classe est vraiment la classe qui définit l'objet référencé par variable.

    De même que, quand tu fais :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Object string = new String("toto");
    string = string.toUpperCase();
    il y a une erreur de compilation sur la ligne en rouge, parce qu'il n'y a pas de méthode toUpperCase() dans la classe Object. Alors que la variable string est bien de la classe String, qui a bien cette méthode.

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

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

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 807
    Points
    48 807
    Par défaut
    Pour faire simple:

    La signature de la méthode est déterminée à la compilation
    L'adresse de la méthode appelée dépendra de l'objet réel.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
      public static void main(String[] argv){
        A a = new B();
        B b = new B();
        a.m(b);
            // appeler la méthode m(A) sur a  (compilation)
            // appeler la méthode B.m(A) sur l'instance de B stockée dans la variable a (runtime)
            // Cette méthode est définie dans B.java
        a.n(b);
            // appeler la méthode n(A) sur a (compilation)
            // appeler la méthode B.n(A) sur l'instance de B stockée dans la variable a
            // cette méthode est définie dans A.java
      }

Discussions similaires

  1. [1.5] Ellipse et liaison dynamique
    Par bulbo dans le forum Langage
    Réponses: 4
    Dernier message: 29/09/2006, 19h09
  2. Liaison dynamique !
    Par Franck.H dans le forum Linux
    Réponses: 2
    Dernier message: 16/08/2006, 14h25
  3. Liaison dynamique et vitesse des programmes
    Par sebzinzin dans le forum Langage
    Réponses: 2
    Dernier message: 11/04/2006, 09h51
  4. Problème de liaison dynamique...
    Par Franck.H dans le forum Linux
    Réponses: 13
    Dernier message: 24/06/2005, 18h45
  5. [xsl]simuler le mecanisme OO de "liaison dynamique"
    Par philemon_siclone dans le forum XSL/XSLT/XPATH
    Réponses: 10
    Dernier message: 19/12/2003, 11h34

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