4 votes

Comment Java détermine-t-il la méthode à invoquer par le biais d'invocations de type implicites ?

Ce problème s'est présenté lorsque moi et mes amis étions en train d'étudier pour des examens. Nous avons remarqué un comportement étrange lors de l'appel d'une méthode d'une variable assignée statiquement.

Code>Mots, c'est parti :

class C {

    public void a(double x) {}
}

class D extends C {
    void b() {} 
}

class F extends D {

    void a(int i) {} 
    void a(double d) {} 

Maintenant, faire

D foo = new F();
foo.a(1);

Qu'est-ce que cela va donner ? Eh bien la méthode fonctionne a(double) en F ! !

Voici ce que nous pensions qu'il s'était passé :

  1. Le programme commence par rechercher a dans le type statique D : il n'y a rien à ce niveau.
  2. Va dans sa super classe, C . Ne trouve pas a(int) mais trouve à la place a(double) .
  3. Décide que c'est la signature dont je parlais (c'est-à-dire a(double)), mais FIIRST, après toute cette recherche, regardons la page dynamique tapez d'abord, c'est écrit !
  4. Courses a(double) en F !

Est-ce exact ? Cela signifie qu'il escalade la hiérarchie pour trouver une méthode qui pourrait convenir si la conversion de type de int à double est faite. APRÈS cela, il vérifie si le type dynamique possède cette signature nouvellement interprétée.

J'ai remarqué que si j'ajoutais

void a(int) {}

** en classe C , cela me donnerait a(int) en F lors de l'exécution de l'invocation ci-dessus !

Quelqu'un peut-il expliquer les mécanismes de ce processus ? Pourquoi le code s'exécute-t-il/compile-t-il de cette manière ? Quelles sont les raisons techniques derrière cela ? Et y a-t-il d'autres choses dont il faut être conscient concernant des circonstances similaires ()

7voto

Antimony Points 13190

La raison en est que Java est typée statiquement. La répartition sur le type d'argument se fait à la compilation, et non à l'exécution.

Lorsque le code est compilé, le compilateur voit que vous invoquez une méthode nommée a sur un objet de type statique D . Il recherche des méthodes compatibles dans D et trouve une seule méthode (héritée de C ). Il génère du code pour effectuer un appel virtuel à C.a(double) .

Au moment de l'exécution, l'appel virtuel porte sur le type réel de l'objet (et non sur les arguments !), de sorte qu'il finit par appeler F.a(double) puisqu'elle est prioritaire par rapport à la C.a(double) .

Le fait que le type d'exécution de l'objet soit F y F a une méthode différente qui aurait été valable si elle avait été connue au moment de la compilation, n'est pas pertinente. Si vous voulez ce comportement, vous avez besoin de la réflexion.

Si vous avez ajouté C.a(int) le compilateur verrait deux méthodes différentes nommées a en D et en se basant sur les règles de surcharge, choisir celui qui prend un int.

4voto

Mark Peters Points 42201

La méthode à appeler est résolue au moment de la compilation, et non de l'exécution. Puisque le compilateur ne sait qu'au moment de la compilation que foo est une méthode D et n'a donc qu'une méthode a(double) c'est la méthode qui est appelée. C'est précisément la méthode de l'objet a(double) à appeler se fait de manière dynamique (au moment de l'exécution). F.a(double) sera appelé et non C.a(double) .

C'est ce qu'on appelle envoi unique : la méthode à appeler est dynamique sur l'objet sur lequel elle est invoquée, mais statique sur ses types d'arguments.

Si vous supprimez cette méthode dans C entièrement, il n'appellerait pas a(int) en F il ne compilerait pas en disant qu'il ne peut pas trouver cette méthode.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X