4
votes

les objets gauche et droit sont évalués / résolus pendant l'exécution ou la compilation?

Se référant à un exercice de livre ...

Avoir le code suivant ..

left.invoke (right);

... et garder à l'esprit que les deux méthodes mentionnées ci-dessus peuvent renvoyer instance de toutes les sous-classes de Left et Right, en Java l'appel de la méthode suivante ...

Left left = createLeftInstance ();
Right right = createRightInstance ();

comment est résolu:

  • A) en se basant sur le type d'exécution à gauche et à la compilation à droite
  • B) en se basant sur le type à la compilation de gauche et d'exécution de droite
  • C) basé sur le type à la compilation de gauche et à la compilation de droite
  • D) basé sur le type d'exécution de gauche et d'exécution de droite


0 commentaires

3 Réponses :


1
votes

A) est la bonne réponse ici.

Le code suivant le montre.

Invoking method A on B2 with argument A2
Done!!!

Cet exemple imprime

    public class Main001 {

        public static void main(String[] args) {
            A right = createRightInstance();
            B left = createLeftInstance();

            left.invoke(right);
            System.out.println("Done!!!");
        }

        public static B createLeftInstance() {
            return new B2();
        }

        public static A createRightInstance() {
            return new A2();
        }

    }

    class A{

    }

    class A1 extends A{

    }

    class A2 extends A1{

    }

    class B{
        public void invoke(A x) {
            System.out.println("Invoking method A on B with argument " + x.getClass().getName());
        }
        public void invoke(A1 x) {
            System.out.println("Invoking method A1 on B with argument " + x.getClass().getName());
        }
        public void invoke(A2 x) {
            System.out.println("Invoking method A2 on B with argument " + x.getClass().getName());
        }
    }

    class B1 extends B{
        public void invoke(A x) {
            System.out.println("Invoking method A on B1 with argument " + x.getClass().getName());
        }
        public void invoke(A1 x) {
            System.out.println("Invoking method A1 on B1 with argument " + x.getClass().getName());
        }
        public void invoke(A2 x) {
            System.out.println("Invoking method A2 on B1 with argument " + x.getClass().getName());
        }

    }

    class B2 extends B1{
        public void invoke(A x) {
            System.out.println("Invoking method A on B2 with argument " + x.getClass().getName());
        }
        public void invoke(A1 x) {
            System.out.println("Invoking method A1 on B2 with argument " + x.getClass().getName());
        }
        public void invoke(A2 x) {
            System.out.println("Invoking method A2 on B2 with argument " + x.getClass().getName());
        }
    }

qui signifie A) est la bonne réponse.

Pourquoi cela signifie-t-il cela?

Eh bien ... parce que:
1) une méthode de la classe B2 est invoquée (comme le dit la sortie) et B2 est le type d'exécution de left (le type de compilation de left est B). 2) une méthode avec le paramètre A est invoquée (notez que A est le type à la compilation de right ), même si le type d'exécution de right est A2. Le type de temps de compilation de right est juste le type avec lequel right est déclaré c.-à-d. A. Le type d'exécution de right est le type réel de l'argument ie A2 (voir la sortie, il dit avec l'argument A2 ici).


3 commentaires

NP. J'espère que vous l'avez compris. Il est bon de connaître ces choses en profondeur sinon certains programmes que vous codez peuvent fonctionner d'une manière complètement différente de celle que vous attendez d'eux :) C'est une question basique mais agréable et délicate.


Je pense que je l'ai compris, mais pas sûr à 100%. Demain, je passerai probablement des heures là-dessus; Je ne passerai sûrement pas au suivant sans le comprendre (ce ne serait pas dans l'ADN d'un programmeur). Si j'ai besoin d'une assistance supplémentaire, je reviendrai vers vous ahah. Vraiment merci!!!


Vous pouvez toujours le relire, jouer vous-même avec des exemples similaires. Cette question concerne le polymorphisme. Je suis sûr que de nombreux développeurs expérimentés peuvent y répondre de manière incorrecte. En gros, la réponse peut être formulée comme suit: vous avez un polymorphisme sur la référence que vous appelez ( gauche ) mais pas sur l'argument que vous passez ( droite ). C'est peut-être le moyen le plus simple de se souvenir de cette règle.



2
votes

En fait, je pense que la réponse techniquement correcte est "aucune des réponses ci-dessus".

  • Lors de la compilation, vous devez connaître les types déclarés de la variable left ( Left ) et de la variable right ( Droite ). Cela déterminera quelle méthode de surcharge 1 de la méthode Left :: invoke est la plus applicable à un paramètre de type Right .

    < / li>
  • Lors de l'exécution, le type réel de left déterminera quelle méthode réelle sera appelée.

La réponse complète est donc:

E) basé sur les types de compilation ET d'exécution de left et sur le type de compilation de right .

Cependant, je soupçonne que le but de cette question dans le manuel est de vous aider à faire la distinction entre la résolution à la compilation des méthodes non surchargées et la répartition des méthodes d'exécution. Pour cela, A) est "assez correct".


1 - Pour effectuer la détermination, le compilateur doit comparer Right et ses supertypes avec les différentes surcharges de méthode de la méthode invoke déclarées par Gauche et ses supertypes. S'il y a plusieurs surcharges, le compilateur doit choisir la surcharge "applicable la plus spécifique".


0 commentaires

0
votes

Java a A , cela s'appelle envoi unique :

  • la surcharge de méthode est sélectionnée par le compilateur, au moment de la compilation (en faisant correspondre le type à la compilation de right aux méthodes proposées par le type de compilation de left code >)
  • l'invocation de la méthode se produit sur le type d'exécution de left - comme les méthodes ne disparaissent pas, left a certainement une méthode avec la même signature qui a été choisie au moment de la compilation . Cet acte compte comme "expédition", et comme il ne dépend que de gauche (à l'exécution), il est "unique".

Démo super simple utilisant println (Object) et println(char[ ):

abc
abc


0 commentaires