Comment les annotations telles que @Override fonctionnent-elles en interne dans Java?


91

Quelqu'un peut-il m'expliquer comment les annotations fonctionnent en interne en Java?

Je sais comment nous pouvons créer des annotations personnalisées en utilisant la bibliothèque java.lang.annotation en java. Mais je ne comprends toujours pas comment cela fonctionne en interne, par exemple, l'annotation @Override.

Je serai vraiment reconnaissant si quelqu'un pouvait expliquer cela en détail.


4
Qu'entendez-vous par «travailler en interne»? Le compilateur? Le runtime?
chrylis -cautouslyoptimistic-

3
@chrylis Work en interne signifie comment il est automatiquement identifié que cette méthode est une méthode de substitution ou que celle-ci n'est pas une méthode de substitution. C'est du travail à la fois. comme le travail d'annotation de remplacement au moment de la compilation et l'annotation du contrôleur de ressort fonctionne à l'exécution
Chirag Dasani

Réponses:


137

La première distinction principale entre les types d'annotations est de savoir s'ils sont utilisés au moment de la compilation puis supprimés (comme @Override) ou placés dans le fichier de classe compilé et disponibles au moment de l'exécution (comme Spring @Component). Ceci est déterminé par la politique @Retention de l'annotation. Si vous écrivez votre propre annotation, vous devez décider si l'annotation est utile au moment de l'exécution (pour la configuration automatique, peut-être) ou seulement au moment de la compilation (pour la vérification ou la génération de code).

Lors de la compilation de code avec des annotations, le compilateur voit l'annotation comme il voit d'autres modificateurs sur les éléments source, comme les modificateurs d'accès ( public/ private) ou final. Lorsqu'il rencontre une annotation, il exécute un processeur d'annotations, qui est comme une classe de plug-in qui dit qu'il est intéressé par une annotation spécifique. Le processeur d'annotations utilise généralement l'API Reflection pour inspecter les éléments en cours de compilation et peut simplement exécuter des vérifications sur eux, les modifier ou générer un nouveau code à compiler. @Overrideest un exemple du premier; il utilise l'API Reflection pour s'assurer qu'il peut trouver une correspondance pour la signature de méthode dans l'une des superclasses et utilise Messagerpour provoquer une erreur de compilation si ce n'est pas le cas.

Il existe un certain nombre de didacticiels sur l'écriture de processeurs d'annotations; en voici une utile . Parcourez les méthodes de l' Processorinterface pour savoir comment le compilateur appelle un processeur d'annotations; l'opération principale a lieu dans la processméthode, qui est appelée à chaque fois que le compilateur voit un élément qui a une annotation correspondante.


4
ce serait bien de nous indiquer exactement comment le processeur d'annotations de Spring analyse le @Component et injecte la classe dans son conteneur
Junchen Liu

@shanyangqu C'est hors sujet pour la question, qui n'est pas spécifique à Spring. Vous pouvez lire vous-même les classes de postprocesseur.
chrylis -cautouslyoptimistic-

41

Outre ce que d'autres ont suggéré, je vous recommande d'écrire une annotation personnalisée et son processeur à partir de zéro pour voir comment fonctionne l'annotation.

Dans le mien, par exemple, j'ai écrit une annotation pour vérifier si les méthodes sont surchargées au moment de la compilation.

Tout d'abord, créez une annotation nommée Overload. Cette annotation est appliquée à la méthode donc je l'annote avec@Target(value=ElementType.METHOD)

package gearon.customAnnotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

@Target(value=ElementType.METHOD)
public @interface Overload {

}

Ensuite, créez le processeur correspondant pour gérer les éléments annotés par une annotation définie. Pour la méthode annotée par @Overload, sa signature doit apparaître plus d'une fois. Ou l'erreur est imprimée.

package gearon.customAnnotation;

import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;

@SupportedAnnotationTypes("gearon.customAnnotation.Overload")

public class OverloadProcessor extends AbstractProcessor{

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        // TODO Auto-generated method stub
        HashMap<String, Integer> map = new HashMap<String, Integer>();

        for(Element element : roundEnv.getElementsAnnotatedWith(Overload.class)){
            String signature = element.getSimpleName().toString();
            int count = map.containsKey(signature) ? map.get(signature) : 0;
            map.put(signature, ++count);
        }

        for(Entry<String, Integer> entry: map.entrySet()){
            if(entry.getValue() == 1){
                processingEnv.getMessager().printMessage(Kind.ERROR, "The method which signature is " + entry.getKey() +  " has not been overloaded");
            }
        }
        return true;
    }
}

Après avoir empaqueté l'annotation et son processus dans un fichier jar, créez une classe avec @Overloadet utilisez javac.exe pour la compiler.

import gearon.customAnnotation.Overload;

public class OverloadTest {
    @Overload
    public static void foo(){
    }

    @Overload
    public static void foo(String s){

    }

    @Overload
    public static void nonOverloadedMethod(){

    }
} 

Comme nonOverloadedMethod()n'a pas été réellement surchargé, nous obtiendrons la sortie comme ci-dessous:

entrez la description de l'image ici


Les informations ci-dessus sont très bonnes par rapport à JDK6 (+1 pour cela), mais comment réaliser la même chose en utilisant JDK5 également? En utilisant JDK6 SupportedAnnotationTypes, classe AbstractProcessor, il est devenu plus simple, mais comment la même chose s'est-elle produite dans le passé (comme Spring FrameWork 2.5 sur jdk5)? Comment JVM détecte-t-il le processeur d'annotation comme la classe dans jdk5? pouvez-vous s'il vous plaît guider en éditant la réponse dans la section 2 (une pour JDK5, la version actuelle est pour Jdk6 +)?
prajitgandhi

Dans votre classe, OverloadProcessor::processpourquoi entry.getValue() == 1? Il n'est pas nécessaire d'ajouter une annotation à la classe / interface parente, doncroundEnv.getElementsAnnotatedWith(Overload.class) n'obtiendra pas la classe / interface parente, non?
pleut

Je suis confus à ce stade, mais je pense que votre réponse est très utile.
pleut

@ s̮̦̩e̝͓c̮͔̞ṛ̖̖e̬̣̦t̸͉̥̳̼ Si une méthode est traitée comme une surcharge, il devrait y avoir au moins une autre méthode avec le même nom défini dans la classe.
Eugene

1
@Raining pour qu'une méthode dise Overloaded, elle doit apparaître plus d'une fois dans la même classe, mais si c'est `== 1` alors c'est une erreur.
KrishPrabakar le

5

Voici @Override: http://www.docjar.com/html/api/java/lang/Override.java.html .

Il n'y a rien de spécial à ce sujet qui le différencie d'une annotation que vous pourriez écrire vous-même. Les bits intéressants sont dans les consommateurs des annotations. Pour une annotation comme @Override, ce serait dans le compilateur Java lui-même, ou dans un outil d'analyse de code statique, ou dans votre IDE.


1
Je connais le code source de l'annotation Override. Mais comment ça marche en interne. comme comment il peut être identifié cette méthode n'est pas une méthode de substitution ou celle-ci est une méthode de substitution? ou puis-je créer mon annotation de remplacement personnalisée? et cela devrait fonctionner exactement le même comportement que l'annotation de remplacement de java
Chirag Dasani

3
Comme je l'ai dit dans ma réponse, le comportement ne fait pas partie de l'annotation. L'interprétation réside dans les choses qui consomment l'annotation. Pour cette raison, à moins que vous ne changiez de consommateur, vous ne pouvez pratiquement pas créer votre propre version personnalisée de @Override(ou d'autres annotations standard).
Matt Ball

3

Fondamentalement, les annotations ne sont que des marqueurs qui sont lus par le compilateur ou l'application. En fonction de leur politique de rétention, ils ne sont disponibles qu'au moment de la compilation ou sont lisibles au moment de l'exécution à l'aide de la réflexion.

De nombreux frameworks utilisent la rétention d'exécution, c'est-à-dire qu'ils vérifient de manière réfléchie si certaines annotations sont présentes sur une classe, une méthode, un champ, etc. et font quelque chose si l'annotation est présente (ou non). De plus, les membres des annotations peuvent être utilisés pour transmettre des informations supplémentaires.


3

Suivez ce lien . Cela fournira une réponse précise à votre problème. Si nous nous sommes concentrés sur les annotations dansJava , les annotations ont été introduites dans Java 5 et ne sont pas spécifiques à Spring. En général, les annotations vous permettent d'ajouter des métadonnées à une classe, une méthode ou une variable. Une annotation peut être interprétée par le compilateur (par exemple, l'annotation @Override) ou par un framework tel que spring (par exemple, l'annotation @Component).

En plus j'ajoute plus de références.

  1. http://www.codeproject.com/Articles/272736/Understanding-Annotations-in-Java
  2. http://docs.oracle.com/javase/7/docs/api/java/lang/annotation/package-summary.html
  3. http://www.coderanch.com/how-to/java/AnnotationsExample

@LuiggiMendoza java 1.7 annotation doc ajouté
Ruchira Gayan Ranaweera

@Ruchira j'ai ouvert tous les liens mais je ne sais toujours pas comment cela fonctionne. Pouvez-vous m'expliquer dans des détails comme considérer comme des annotations de printemps. Je peux tout faire en utilisant l'annotation sans écrire de configuration dans le fichier spring.xml. est-il lié en interne à l'annotation à la configuration xml?
Chirag Dasani

@ChiragDasani jetez un œil à cela. cela peut vous aider static.springsource.org/spring/docs/3.0.0.M3/reference/html/… et aussi voir ce message SO stackoverflow.com/questions/2798181/…
Ruchira Gayan Ranaweera

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.