web-dev-qa-db-fra.com

Comment des annotations telles que @Override fonctionnent-elles en Java?

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

Je sais comment créer des annotations personnalisées à l'aide de 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 serais vraiment reconnaissant si quelqu'un pouvait expliquer cela en détail.

76
Chirag Dasani

La première distinction importante entre les types d’annotation est qu’ils sont utilisés au moment de la compilation et ensuite ignorés (comme @Override) ou placé dans le fichier de classe compilé et disponible 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 devrez décider si elle est utile au moment de l'exécution (pour la configuration automatique, par exemple) ou uniquement 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 de la même manière que les autres modificateurs d'éléments sources, tels que les modificateurs d'accès (public/private) ou final. Lorsqu'il rencontre une annotation, il exécute un processeur d'annotation, qui ressemble à une classe de plug-in qui indique qu'une annotation spécifique l'intéresse. Le processeur d'annotation utilise généralement l'API Reflection pour inspecter les éléments en cours de compilation et peut simplement exécuter des contrôles sur eux, les modifier ou générer un nouveau code à compiler. @Override est un exemple du premier; il utilise l'API Reflection pour s'assurer qu'il peut trouver une correspondance pour la signature de la méthode dans l'une des superclasses et utilise le Messager pour provoquer une erreur de compilation s'il ne le peut pas.

Un certain nombre de tutoriels sont disponibles sur l’écriture de processeurs d’annotation; voici un utile . Regardez à travers les méthodes sur l'interface Processor pour savoir comment le compilateur appelle un processeur d'annotation; l'opération principale a lieu dans la méthode process, appelée à chaque fois que le compilateur voit un élément ayant une annotation correspondante.

120
chrylis

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

Dans mon cas, 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 @Overload Et 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(){

    }
} 

Puisque nonOverloadedMethod() n'a pas été surchargé, nous allons obtenir le résultat comme ci-dessous:

enter image description here

31
Gearon

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 un outil d'analyse de code statique, ou votre IDE).

4
Matt Ball

Suivez ceci lien . Cela fournira une réponse précise à votre problème. Si nous nous sommes concentrés sur les annotations dans Java, 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 cadre 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
3

Fondamentalement, les annotations ne sont que des marqueurs qui sont lus par le compilateur ou l'application. Selon leur stratégie de rétention, ils sont disponibles 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 agissent 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
Thomas