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

Java Discussion :

Appel d'une méthode sur une classe avec héritage


Sujet :

Java

  1. #1
    Candidat au Club
    Homme Profil pro
    Devops
    Inscrit en
    Août 2013
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Août 2013
    Messages : 6
    Points : 3
    Points
    3
    Par défaut Appel d'une méthode sur une classe avec héritage
    Bonjour,

    Tout d'abord, désolé pour le titre confus, je ne sais trop comment intituler correctement ce soucis...
    Prenons l'exemple suivant :
    Code Java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    package test;
     
    public class ExtendsStaticTest
    {
     
        /**
         * @param args
         */
        public static void main(String[] args)
        {
            B.foo();
            A.getB().foo();
        }
    }

    Code Java : 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
     
    package test;
     
    public class A
    {
     
        protected static void foo()
        {
            System.out.println("bar");
        }
     
        public static A getB()
        {
            return new B();
        }
    }

    Code Java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    package test;
     
    public class B
        extends A
    {
        protected static void foo()
        {
            System.out.println("barB");
        }
    }

    Selon moi, l'appel à A.getB() me retourne une instance de B, instance dont la classe hérite de A.
    A.getB().foo() fait cependant appel à la méthode de la classe A...

    Pourquoi et comment faire pour que ce soit la méthode B.foo() qui soit appelée ?


    Le soucis réel caché derrière cet ECM est qu'au lieu d'avoir A.getB(), j'ai A.getUneClasse() dont le retour peut être soit une instance de A, soit une instance de B; où B s'agirait d'une classe surchargée par un utilisateur.


    Avez vous des explications à me fournir sur ce comportement que je ne comprends pas ?

    Merci

  2. #2
    Membre expert

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2004
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 2 301
    Points : 3 675
    Points
    3 675
    Par défaut
    Le polymorphisme ne s'applique pas dans le cas de méthodes statiques. C'est le type déclaré à la compilation qui est exécuté, pas le type réel.

    Early binding vs late binding ==> le static est linké, figé dans le marbre, au moment de la compilation. Tout comme d'ailleurs le polymorphisme paramètrique (avoir 2 signatures void foo(Object o) et void foo(String s), que se passe-t-il quand on invoque avec une variable de type Object qui contient en réalité une String??)

    "Le plug gros problème des citations trouvées sur internet, c'est qu'on ne peut jamais garantir leur authenticité"

    Confucius, 448 av. J-C

  3. #3
    Candidat au Club
    Homme Profil pro
    Devops
    Inscrit en
    Août 2013
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Août 2013
    Messages : 6
    Points : 3
    Points
    3
    Par défaut
    Merci pour ta réponse.
    Du coup, si je te comprends bien, le soucis est lié au fait que ma méthode A.getB() soit statique...

    Admettons que je crée la fonction suivante dans la classe A

    Code Java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
        public A getBNoStatic()
        {
            return new B();
        }

    L'appel à new A().getBNoStatic().foo(); ne devrait-il pas alors valoir la même chose que B.foo(); ?
    Pourtant cela me renvoie vers A.foo();

    J'ai actuellement la main sur getB() de la classe A ainsi que sur la classe B.
    Par contre, je n'ai pas la main sur le reste de la classe A pour raison de rétrocompatibilité...
    foo() est une méthode statique et je ne peux pas le modifier.

    Merci


    Edit : Pas sûr d'avoir tapé à coté de ton explication... en fait, A.getB() pourrait ou non être statique on s'en fiche mais c'est foo() qui, étant statique, empêche d'appeler correctement A.foo() ou B.foo() ?

    Ai-je un moyen de faire autrement ?

  4. #4
    Modérateur

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

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Hello

    Citation Envoyé par SasakiKojiro Voir le message
    [...] en fait, A.getB() pourrait ou non être statique on s'en fiche mais c'est foo() qui, étant statique, empêche d'appeler correctement A.foo() ou B.foo() ?
    Yup. Cela dit, c'est une mauvaise chose d'appeler A.getB(). Une méthode statique s'appelle en fonction de son nom de classe, pas d'un objet.

    Citation Envoyé par SasakiKojiro Voir le message
    Ai-je un moyen de faire autrement ?
    B.foo(), et puis c'est tout. De toute façon c'est elle que tu veux appeler, pas une autre, alors pourquoi chercher ailleurs ?
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  5. #5
    Membre expert

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2004
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 2 301
    Points : 3 675
    Points
    3 675
    Par défaut
    Tu pourrais forcer via un cast, mais c'est moche... ((B)A.getBNoStatic()).foo()En plus c'est vrai, si c'est statique, faut invoquer de manière statique... en référençant la classe et pas une instance
    "Le plug gros problème des citations trouvées sur internet, c'est qu'on ne peut jamais garantir leur authenticité"

    Confucius, 448 av. J-C

  6. #6
    Candidat au Club
    Homme Profil pro
    Devops
    Inscrit en
    Août 2013
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Août 2013
    Messages : 6
    Points : 3
    Points
    3
    Par défaut
    Citation Envoyé par thelvin Voir le message
    Hello
    B.foo(), et puis c'est tout. De toute façon c'est elle que tu veux appeler, pas une autre, alors pourquoi chercher ailleurs ?
    Par défaut, la classe A existe et est la référence. Il se peut que pour un besoin spécifique, l'utilisateur ait définit une classe B et souhaite ne pas appeler A.foo() mais B.foo()
    Donc s'il a défini B, je dois utiliser B.
    Au final, je sais seulement que je vais appeler la méthode foo() mais pour certains utilisateurs ça viendra de A, pour d'autre de B.

    Citation Envoyé par Pill_S Voir le message
    Tu pourrais forcer via un cast, mais c'est moche... ((B)A.getBNoStatic()).foo()En plus c'est vrai, si c'est statique, faut invoquer de manière statique... en référençant la classe et pas une instance
    Pareil, si je force le cast, j'empêche le fait de pouvoir avoir A.foo().
    Je suis désolé, je suis pas vraiment clair... J'avais expliqué que je n'ai pas vraiment de A.getB() mais un A.getUneClasse() et que, si l'utilisateur a défini la classe B, la méthode me retourne B; A sinon.

    A n'étant pas un B, ((B)A.getBNoStatic()).foo() me renverra une classCastException

  7. #7
    Membre expérimenté Avatar de Nico02
    Homme Profil pro
    Developpeur Java/JEE
    Inscrit en
    Février 2011
    Messages
    728
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Developpeur Java/JEE
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2011
    Messages : 728
    Points : 1 622
    Points
    1 622
    Par défaut
    Salut,

    Je sais pas si j'ai bien compris mais pour moi le seul moyen c'est d'utiliser la réflexion sur l'appel de la méthode.

    Ex:

    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 A
    {
     public static void foo() { System.out.println( "A" ); }
    }
     
    public class B extends A
    {
     public static void foo() { System.out.println( "B" ); }
    }
     
    A a = new A();
    A b = new B();
    Class<?> clazz;
     
    clazz = Class.forName( a.getClass().getName() );
     
    Method method = clazz.getMethod( "foo", null );
     
    method.invoke( null, null ); // Donne A.foo()
     
    clazz = Class.forName( b.getClass().getName() );
    method = clazz.getMethod( "foo", null );
    method.invoke( null, null ); // Donne B.foo()
    Dans le cas où B ne contient pas la méthode foo(), alors le deuxième appel renvoie A.foo()

  8. #8
    Membre expert

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2004
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 2 301
    Points : 3 675
    Points
    3 675
    Par défaut
    Oui bonne idée la réflexion, bien vu...

    Mais fondamentalement, c'est quand même très faux de vouloir un mécanisme OO et d'avoir tout en statique... tu peux pas challenger la personne en charge de ton api pour peut-être enlever le statique?
    "Le plug gros problème des citations trouvées sur internet, c'est qu'on ne peut jamais garantir leur authenticité"

    Confucius, 448 av. J-C

  9. #9
    Membre expérimenté Avatar de Nico02
    Homme Profil pro
    Developpeur Java/JEE
    Inscrit en
    Février 2011
    Messages
    728
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Developpeur Java/JEE
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2011
    Messages : 728
    Points : 1 622
    Points
    1 622
    Par défaut
    Citation Envoyé par Pill_S Voir le message
    Oui bonne idée la réflexion, bien vu...

    Mais fondamentalement, c'est quand même très faux de vouloir un mécanisme OO et d'avoir tout en statique... tu peux pas challenger la personne en charge de ton api pour peut-être enlever le statique?
    Je suis bien d'accord.. Après j'imagine que personne ne respecte vraiment tous les paradigmes OO à la lettre donc bon..

  10. #10
    Membre expert

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2004
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 2 301
    Points : 3 675
    Points
    3 675
    Par défaut
    Citation Envoyé par Nico02 Voir le message
    Après j'imagine que personne ne respecte vraiment tous les paradigmes OO à la lettre donc bon..
    oui c'est sûr... mais ça vaut le coup de demander/confirmer... peut-être que le gars peut rajouter une méthode non-statique à côté, qui s'occupe d'invoquer la méthode statique qui-va-bien? genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    class A {
        static void foo() {}
        public void fooPasCassé() { A.foo(); }
    }
    class B extends A {
        static void foo() {}
        public void fooPasCassé() { B.foo(); }
    }
    ... et du coup polymorphisme-powered...

    Souvent, on ne peut pas enlever ni changer la signature des méthodes d'une api publiée. Mais c'est rarissime de ne pas pouvoir en ajouter

    j'ai souvent eu des soucis avec de la réflexion mal placée... c'est puissant mais ça a son lot de défauts... et si on peut s'en passer... mazeltov!
    "Le plug gros problème des citations trouvées sur internet, c'est qu'on ne peut jamais garantir leur authenticité"

    Confucius, 448 av. J-C

  11. #11
    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 SasakiKojiro Voir le message
    Merci pour ta réponse.
    Du coup, si je te comprends bien, le soucis est lié au fait que ma méthode A.getB() soit statique...
    Non, il est lié au fait que la méthode foo() soit statique. Une méthode statique s'appelle via la classe et non via l'instance. C'est tout simplement à considérer comme une erreur d'écrire si foo est statique et un bon ide va te mettre un bon gros warning là dessus.

    Ai-je un moyen de faire autrement ?
    De la manière la plus simple, avec un if vu ton explication.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    if (a instanceof b){
     B.foo();
    } else {
     A.foo();
    }
    Citation Envoyé par SasakiKojiro Voir le message
    Par défaut, la classe A existe et est la référence. Il se peut que pour un besoin spécifique, l'utilisateur ait définit une classe B et souhaite ne pas appeler A.foo() mais B.foo()
    Donc s'il a défini B, je dois utiliser B.
    Je vois déjà deux chose:
    foo() dois pouvoir être redéfini
    l'appel foo() est fonction de l'instance de A/B dont on dispose à l'instant T
    deux raison qui font que foo n'a aucune raison d'être statique. Je voudrais quand même bien voir le cas concret car soit t'as mal compris l'utilisation de A, soit A a été très très mal architecturée.

    Citation Envoyé par Nico02 Voir le message
    Salut,

    Je sais pas si j'ai bien compris mais pour moi le seul moyen c'est d'utiliser la réflexion sur l'appel de la méthode.
    Non seulement ce code va galérer, faire sauter toutes les vérifications du compilateur et être complexe à réaliser en prenant tout en compte (on fait quoi des Proxy dynamiques par exemple?), mais la reflection ne devrait pas être utilisée pour palier un problème de design.

    Faudrait plus de code pour fournir une solution propre et si on va pour le moche, autant y aller avec un if sur toutes les sous classes connues plutot que de passer par une reflection complexe et douloureuse.

  12. #12
    Membre expert

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2004
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 2 301
    Points : 3 675
    Points
    3 675
    Par défaut
    Citation Envoyé par tchize_ Voir le message
    De la manière la plus simple, avec un if vu ton explication.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    if (a instanceof b){
     B.foo();
    } else {
     A.foo();
    }
    comme je l'ai compris, B n'est pas connu à la compilation... correct?
    "Le plug gros problème des citations trouvées sur internet, c'est qu'on ne peut jamais garantir leur authenticité"

    Confucius, 448 av. J-C

  13. #13
    Membre expérimenté Avatar de Nico02
    Homme Profil pro
    Developpeur Java/JEE
    Inscrit en
    Février 2011
    Messages
    728
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Developpeur Java/JEE
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2011
    Messages : 728
    Points : 1 622
    Points
    1 622
    Par défaut
    Citation Envoyé par Pill_S Voir le message
    comme je l'ai compris, B n'est pas connu à la compilation... correct?
    C'est ce que j'ai compris aussi.

    mais la reflection ne devrait pas être utilisée pour palier un problème de design
    J'ai pas dit non plus que c'était the best solution ever. Mais on sait tous que parfois on a pas vraiment le choix..

    Après comme tu le signales, il faudrait un exemple plus concret pour voir si il y a mieux à faire.

  14. #14
    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
    ouais sauf que là visiblement, j'ai l'impression que c'est lui qui définis dans son code qu'on peux étendre une fonction statique, ça n'a jamais été prévu par la librairie de base, donc il se fourvoie donc il peut se corriger plutot que de sortir cette horreur qui va pêter de partout.

Discussions similaires

  1. [WD18] Metre une colonne d'une Table sur une ligne d'une autre Table
    Par Totophe2 dans le forum WinDev
    Réponses: 2
    Dernier message: 22/11/2013, 12h58
  2. Problème de thread sur une méthode d'une classe C++
    Par yoshi84300 dans le forum Threads & Processus
    Réponses: 5
    Dernier message: 12/03/2013, 11h23
  3. Appel d'une méthode sur une classe fille
    Par Tipha dans le forum C++
    Réponses: 5
    Dernier message: 29/05/2008, 14h23
  4. Réponses: 6
    Dernier message: 05/03/2008, 20h53
  5. Réponses: 6
    Dernier message: 20/04/2007, 15h24

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