3
votes

Quelle méthode est choisie dans un polymorphisme lors de l'appel d'une méthode disponible dans la classe parent et la classe enfant?

Je ne comprends pas pourquoi la méthode ab.m3 () appelle la fonction de la classe parent et non celle de l'enfant. J'ai pensé que passer un nouvel Integer à la méthode pourrait appeler la méthode de la classe parente car Integer est un Object alors je l'ai essayé avec un int mais cela m'a quand même donné le même résultat!

B.m1
A.m2
A.m3
A.m3

Sortie:

public class A {

    public void m1(){
        System.out.println("A.m1");
    }
    public void m2(){
        System.out.println("A.m2");
    }
    public void m3(Object x){
        System.out.println("A.m3");
    }
}

public class B extends A{

    public void m1(){
        System.out.println("B.m1");
    }
    public void m2(int x){
        System.out.println("B.m2");
    }
    public void m3(int x){
        System.out.println("B.m3");
    }

    public static void main(String[] argv){
        A aa = new A();
        A ab = new B();

        int num = 2;

        ab.m1();
        ab.m2();
        ab.m3(new Integer(2));
        ab.m3(num);

    }
}


3 commentaires

A.m3 (Object)! = B.m3 (int) , c'est-à-dire que vous ne remplacez pas m3 dans B .


Vous devriez prendre l'habitude d'annoter les méthodes qui sont remplacées par @Override . Ensuite, le compilateur peut indiquer si vous l'avez fait correctement (comme c'est le cas ici).


Même si vous ajoutiez la surcharge void m3 (Integer x) dans B , elle ne remplacerait pas A.m3 (Object) en Java a des remplacements de type de retour covariants mais pas de remplacements de paramètres contravariants. Le meilleur conseil est d'éviter la surcharge lorsque cela est possible.


3 Réponses :


0
votes

Votre référence ab est de type A .

Lors de la compilation de ab.m3 (num); , le compilateur ne regarde pas le type d'objet. En général, il ne saura pas toujours quel est le type d'objet. Au lieu de cela, il regarde le type de référence. Il ne peut pas correspondre à B.m3 (int) , car le type de référence n'est pas de type B.

Le compilateur choisit donc la méthode A.m3 (Object) , qui pourrait être surchargée lors de l'exécution. Mais ce n'est pas le cas, donc l'implémentation A est appelée.


0 commentaires

3
votes

B.m3 ne remplace pas A.m3 , car les listes de paramètres ne sont pas compatibles.

Parce que la seule méthode correspondante dans A est A.m3 , et comme il n'y a pas de remplacement dans B , c'est A.m3 qui sera appelé.


1 commentaires

Ce. Fondamentalement, Java regarde toujours le type déclaré lors du choix de la méthode à appeler. Parce que toutes les méthodes en Java sont virtuelles, s'il choisit m1 () de A et que le type d'exécution est B, il appellera à la place m1 () de B car il remplace celui de A.



0
votes

Cet exemple de code est particulièrement déroutant car, bien que l'intention soit de démontrer la substitution , il démontre en fait la surcharge .

Parce que B.m3 (int ) ne correspond pas à la signature de A.m3 (Object) (voir JLS 8.4.8.1 ), la méthode n'est pas remplacée . Au lieu de cela, elle est surchargée.

Mais pourquoi l'appel de la méthode avec un argument int ne sélectionne-t-il pas le bon? Dans cette version simplifiée du code:

B ab = new B();
ab.m3(2);

l'argument de m3 est un int , il ressemble donc au la signature doit correspondre à B.m3 (int) . Pourtant, comme correctement affirmé dans la question, c'est A.m3 (Object) qui est appelé. La raison en est qu'en cas de surcharge , la sélection de la méthode est basée sur le type statique des références d'objet , et non sur le type d'exécution comme pour le remplacement.

Comme le type statique de ab est A , l'algorithme de sélection de méthode commence à rechercher une méthode m3 dans la classe A . Le seul qu'il trouve est m3 (Object) , mais à cause de l'autoboxing, l'argument peut être adapté pour correspondre à la signature, donc le code se compile.

Donc, si vous changez le code et déclarez simplement ab comme étant de type B:

A ab = new B();
ab.m3(2);

alors, surprise, c'est B. m3 (int) qui est appelé.

En raison de ce potentiel de confusion profonde, cette situation doit être évitée à tout prix et de nombreux outils et fonctionnalités sont disponibles pour vous aider. L'annotation @Override en est un exemple. De nombreux IDE ont également des décorations de gouttière pour indiquer le remplacement (comme illustré ci-dessous avec un triangle vert pour Eclipse).

décoration de gouttière pour remplacement dans Eclipse


0 commentaires