À propos de la liaison de méthode Java

Aujourd'hui, je vais écrire un article sur les liaisons de méthodes Java. J'étudie généralement Java et je n'en étais pas vraiment conscient, je vais donc l'organiser correctement pour le moment.

Connaissance préalable

Passons en revue le casting en tant que connaissance préalable. Les casts ont des conversions de type explicites et implicites. Veuillez consulter l'URL suivante pour plus de détails. https://techacademy.jp/magazine/28486 Vous devez également connaître le timing au moment de la compilation et de l'exécution. La compilation correspond au moment où le fichier Java que vous avez écrit est converti en code octet. L'exécution est le moment où la JVM exécute réellement le code d'octet. Si vous développez dans Eclipse, vous écrivez généralement le code et il sera compilé sans autorisation, et le code sera exécuté lorsque vous appuyez sur le bouton d'exécution. Lors du développement dans un terminal, etc., compilez avec la commande javac, créez un fichier de classe et exécutez-le réellement avec la commande java. Les termes «lier» et «lier» utilisés dans l'article ont tous la même signification. (Je suis désolé, c'est déroutant ...)

Qu'est-ce que la liaison de méthode en premier lieu?

Je ne connaissais même pas la signification de ce mot, mais en termes simples, c'est comme un mécanisme en Java qui connecte (lie) un appel de méthode, la signature de la méthode appelée et la partie implémentation. La signature est le nom de la méthode + l'argument, et la partie implémentation est le traitement à l'intérieur de {}. La méthode est un morceau de ces deux, mais pensez séparément pour le moment. Si vous ne comprenez pas cela, vous risquez de tomber dans des endroits inattendus (même si je ne suis pas encore ingénieur, donc je ne peux pas dire que c'est génial ...). Regardons cela concrètement.

Animal.java


public class Animal {
      public void eat(double quantity) {
             System.out.println("Animaux" + quantity + "porte.");
      }
}

Human.java


public class Human extends Animal {
      public void eat(int quantity) {
            System.out.println("Les gens sont" + quantity + "porte.");
      }
}

Test.java


public class Test {
     public static void main(String[] args) {
           Animal animal = new Human();
           int quantity = 500;
           animal.eat(quantity);  // ?
     }
}

Supposons que toutes les classes soient dans le même package. Quel sera le résultat lorsque j'exécuterai Test.java ici? Et pourquoi?

Liaison de méthode

La bonne réponse est "L'animal a mangé 500,0 g." Pourquoi. Au début, je pensais que l'humain était assigné comme référence, donc le résultat devrait être "L'homme a mangé 500g." Le type int est également passé comme argument dans la classe Test. Mais en réalité, la réponse était différente. Regardons quand les liaisons de méthodes se produisent en Java pour comprendre ce qui s'est passé. Consultez le tableau ci-dessous.

Type de méthode Liaison au moment de la compilation Liaison au moment de l'exécution
non-méthode statique Signature de méthode Implémentation de la méthode
méthode statique Signature de méthode, implémentation de méthode

Puisque manger est une méthode non statique cette fois, je vais expliquer sur cette base (l'idée est la même pour les méthodes statiques).

Liaison au moment de la compilation

Java associe la méthode appelée à sa signature au moment de la compilation. En d'autres termes, on peut dire que le compilateur détermine à chaque fois la signature de la méthode appelée. Considérez cette règle avec le code que nous examinons actuellement. La dernière ligne de Test.java ressemble à ceci:

Test.java


animal.eat(quantity);

Tout d'abord, le compilateur examine le type de déclaration (type) de la variable animal. Le type d'animal est de type animal. Le compilateur commence alors la recherche, "Ouais, ouais. Cette variable est le type de la classe Animal. Voyons s'il y a une méthode dans cette classe qui est actuellement appelée." À ce stade, la plage de recherche comprend également des méthodes compatibles avec la méthode appelée. En fait dans la classe Animal

Animal.java


eat(double quantity)

La signature est définie. Dans l'appelant, le type int est passé à l'argument, mais la conversion de int en double est effectuée arbitrairement (sans conversion explicite), de sorte que le compilateur dit: «C'est la méthode qui est appelée maintenant. C'est une méthode compatible avec ", et elle relie l'appel de méthode de animal.eat (quantité) à la méthode eat (signature) qui prend le type double comme argument. À ce stade, le compilateur a déterminé que l'argument eat est de type double. Et il ne peut plus être modifié lors de l'exécution. Vérifions-le réellement.

Compiled from "Test.java"
public class Test {
  public Test();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class Human
       3: dup
       4: invokespecial #3                  // Method Human."<init>":()V
       7: astore_1
       8: sipush        500
      11: istore_2
      12: aload_1
      13: iload_2
      14: i2d
      15: invokevirtual #4                  // Method Animal.eat:(D)V
      18: return
}

Il compile chaque fichier avec la commande javac du terminal, puis examine le contenu du code compilé avec javap -c Test. Voici les lignes dont vous devez être conscient.

15: invokevirtual #4                  // Method Animal.eat:(D)V

Cela correspond à la partie d'appel de méthode dans la classe Test, animal.eat (quantité). (D) indique que l'argument est de type double et V indique que la valeur de retour est void. invokevirtual signifie que l'implémentation réelle est déterminée au moment de l'exécution. Le code est exécuté au Runtime selon les instructions de ce code d'octet. En d'autres termes, dans le compilateur, comme décrit ci-dessus, le contenu du processus est déterminé par la JVM au moment de l'exécution en l'associant simplement à "La méthode appelée est la méthode Animal eat".

Liaison d'exécution

Tout ce que vous avez à faire est d'exécuter la méthode animal.eat (quantité) selon les instructions du code d'octet. Plus tôt, j'ai dit que le compilateur examinait le type de déclaration de la variable animal. La machine virtuelle Java démarre la recherche sur l'objet affecté. En d'autres termes

Test.java


Animal animal = new Human();

Le compilateur regarde le côté gauche (Animal) de cette expression pour faire une série de liaisons, tandis que la JVM regarde d'abord l'objet sur le côté droit (Human). Puis, puisqu'il s'agit d'un objet de la classe Human, il essaie de trouver la méthode de manger: (D) V dans la classe Human. D'autre part, puisque la classe Human contient eat: (I) V (I est un type int), aucune méthode de correspondance ne peut être trouvée. Par conséquent, la machine virtuelle Java recherche la méthode correspondante dans la relation d'héritage. En d'autres termes, si vous regardez la classe parente dont la classe hérite et si elle n'est pas là, vous allez voir la classe parente, et ainsi de suite, en remontant la hiérarchie et en cherchant manger: (D) V. Dans ce cas, il y avait une méthode correspondante dans la classe Animal qui est montée d'un niveau, donc la partie implémentation est liée à la méthode appelante (animal.eat (quantité)) et le traitement est exécuté. En conséquence, le résultat était "L'animal a mangé 500,0 g."

Exemple de liaison de méthode

Enfin, regardons un exemple de liaison de méthode.

List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
System.out.println(list); // [1, 2, 3, 4]

list.remove(3);
System.out.println(list); // [1, 2, 3]

La méthode de suppression de type List est surchargée avec deux méthodes qui acceptent différents types d'arguments, List.remove (index int) et List.remove (Object o) (https://docs.oracle.com/javase). /jp/8/docs/api/java/util/List.html). Ici, remove a un argument de type int, donc list.remove (3) et List.remove (index int) sont liés au moment de la compilation. Et à l'exécution, le traitement (partie implémentation) dans ArrayList.remove (index int) est lié à list.remove (3). En conséquence, le 4 dans le troisième index de cette liste est supprimé et affiché comme [1, 2, 3]. Rien n'a changé jusqu'à présent. Mais qu'en est-il de l'exemple suivant?

Collection<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
System.out.println(list); // [1, 2, 3, 4]

list.remove(3);
System.out.println(list); // [1, 2, 4] ← ??

La seule chose qui a changé est que le conteneur de liste est passé d'un type de liste à un type de collection. Le résultat est affiché sous la forme [1, 2, 4]. Le numéro 3 lui-même a été supprimé, pas le troisième de l'index. En effet, Collection n'a qu'une seule méthode de suppression, Collection.remove (Object o). Le compilateur lie list.remove (3) avec la méthode remove qui prend ce type Object comme argument. Par conséquent, l'argument 3 de list.remove (3) est traité comme un objet, pas comme un index. Lorsque vous le vérifiez avec la commande javap comme auparavant, il sera affiché sous la forme Collection.remove: (Ljava / lang / Object;) Z (Z est un type booléen). Ensuite, selon les instructions du bytecode, ArrayList.remove (Object o) est maintenant exécuté par la JVM au lieu de ArrayList.remove (index int). En conséquence, [1, 2, 4] était affiché à l'écran. Si vous ne connaissiez pas la liaison de méthode, vous avez peut-être programmé en supposant que le troisième index serait normalement supprimé. Si cela se produit, cela entraînera une panne. J'ai pensé que ce serait un grand avantage de connaître ce mécanisme pour l'éviter, j'ai donc écrit cet article. Merci d'avoir lu jusqu'ici.

Recommended Posts

À propos de la liaison de méthode Java
A propos des méthodes de fractionnement (Java)
Méthode Java
java (méthode)
[Java Silver] À propos de la méthode equals
Méthode Java
[Java] méthode
[Java] méthode
À propos de l'interface Java
[Java] À propos des tableaux
Référence de la méthode Java8
Quelque chose à propos de java
Où est Java
À propos des fonctionnalités Java
À propos de la méthode
[Java] méthode forEach
À propos des threads Java
Interface [Java]
À propos de la classe Java
À propos des tableaux Java
À propos de l'héritage Java
À propos de l'interface, interface java
référence de la méthode java8
[Java] Méthode aléatoire
[Java] méthode de fractionnement
À propos de Java Var
À propos de Java Literal
À propos des commandes Java
À propos de la sortie du journal Java
À propos de l'interface fonctionnelle Java
À propos de Aucune erreur de méthode
Java, à propos d'un tableau à deux dimensions
À propos de la division de classe (Java)
Méthode de connexion JAVA DB
À propos de [Java] [StreamAPI] allMatch ()
À propos de la classe Java StringBuilder
Java Learning 2 (Apprenez la méthode de calcul)
[Java] À propos de la classe Singleton
Mémo d'apprentissage Java (méthode)
[Java] À propos des classes anonymes
Etudier Java 8 (voir méthode)
[Java Silver] À propos de l'initialisation
À propos de la méthode de longueur
A propos de la liste des baies Java
À propos du polymorphisme Java Super ()
À propos de l'héritage (Java Silver)
Programmation Java (méthode de classe)
À propos de la classe Java String
À propos des modificateurs d'accès Java
À propos des expressions Java lambda
À propos des points d'entrée Java
Prise en charge de Java 10 Docker
Résumé personnel sur Java
À propos de la méthode cartographique
À propos de la méthode des ancêtres
Tout sur la programmation Java
[Java] Notes de méthode de base