Recherche…


Introduction

En Java, une annotation est une forme de métadonnées syntaxiques pouvant être ajoutées au code source Java. Il fournit des données sur un programme qui ne fait pas partie du programme lui-même. Les annotations n'ont aucun effet direct sur le fonctionnement du code qu'elles annotent. Les classes, méthodes, variables, paramètres et packages peuvent être annotés.

Syntaxe

  • @AnnotationName // 'Annotation du marqueur' (pas de paramètres)
  • @AnnotationName (someValue) // définit le paramètre avec le nom 'value'
  • @AnnotationName (param1 = valeur1) // paramètre nommé
  • @AnnotationName (param1 = valeur1, param2 = valeur2) // plusieurs paramètres nommés
  • @AnnotationName (param1 = {1, 2, 3}) // paramètre de tableau nommé
  • @AnnotationName ({value1}) // tableau avec un seul élément comme paramètre avec le nom 'value'

Remarques

Types de paramètres

Seules les expressions constantes des types suivants sont autorisées pour les paramètres, ainsi que les tableaux de ces types:

  • String
  • Class
  • types primitifs
  • Types enum
  • Types d'annotation

Annotations intégrées

L'édition Standard de Java comporte des annotations prédéfinies. Vous n'avez pas besoin de les définir vous-même et vous pouvez les utiliser immédiatement. Ils permettent au compilateur de permettre une vérification fondamentale des méthodes, des classes et du code.

@Passer outre

Cette annotation s'applique à une méthode et dit que cette méthode doit remplacer une méthode de superclasse ou implémenter une définition de méthode de superclasse abstraite. Si cette annotation est utilisée avec un autre type de méthode, le compilateur générera une erreur.

Superclasse en béton

public class Vehicle {
   public void drive() {
        System.out.println("I am driving");
   }
}

class Car extends Vehicle {
    // Fine
    @Override
    public void drive() {
        System.out.prinln("Brrrm, brrm");
    }
}

Classe abstraite

abstract class Animal  {
   public abstract void makeNoise(); 
}

class Dog extends Animal {
    // Fine
    @Override
    public void makeNoise() {
        System.out.prinln("Woof");
    }
}

Ne marche pas

class Logger1 {
    public void log(String logString) {
        System.out.prinln(logString);
    }
}

class Logger2 {
    // This will throw compile-time error. Logger2 is not a subclass of Logger1. 
    // log method is not overriding anything
    @Override
    public void log(String logString) {
        System.out.println("Log 2" + logString);
    }
}

L'objectif principal est de détecter les erreurs de frappe, où vous pensez que vous écrasez une méthode, mais en en définissant une nouvelle.

class Vehicle {
   public void drive() {
        System.out.println("I am driving");
   }
}

class Car extends Vehicle {
    // Compiler error. "dirve" is not the correct method name to override.
    @Override
    public void dirve() {
        System.out.prinln("Brrrm, brrm");
    }
}

Notez que la signification de @Override a changé avec le temps:

  • Dans Java 5, cela signifiait que la méthode annotée devait remplacer une méthode non abstraite déclarée dans la chaîne de la superclasse.
  • A partir de Java 6, il est également satisfait si la méthode annotée implémente une méthode abstraite déclarée dans la hiérarchie des classes / interfaces des classes.

(Cela peut occasionnellement poser problème lors du portage du code vers Java 5.)

@Précis

Cela marque la méthode comme obsolète. Il peut y avoir plusieurs raisons à cela:

  • l'API est imparfaite et difficile à réparer,

  • l'utilisation de l'API est susceptible de conduire à des erreurs,

  • l’API a été remplacée par une autre API,

  • l'API est obsolète,

  • l'API est expérimentale et est sujette à des modifications incompatibles,

  • ou toute combinaison de ce qui précède.

La raison spécifique de l'abandon se trouve généralement dans la documentation de l'API.


L'annotation provoquera une erreur du compilateur si vous l'utilisez. Les IDE peuvent également mettre en évidence cette méthode d'une manière ou d'une autre

class ComplexAlgorithm {
    @Deprecated
    public void oldSlowUnthreadSafeMethod() {
        // stuff here
    }
    
    public void quickThreadSafeMethod() {
        // client code should use this instead
    }
}

@Supprimer les avertissements

Dans presque tous les cas, lorsque le compilateur émet un avertissement, l'action la plus appropriée consiste à corriger la cause. Dans certains cas (code Generics utilisant du code pré-générique non sécurisé, par exemple), cela peut ne pas être possible et il est préférable de supprimer les avertissements que vous attendez et que vous ne pouvez pas corriger. Vous pouvez donc voir plus clairement les avertissements inattendus.

Cette annotation peut être appliquée à une classe, une méthode ou une ligne entière. Il prend la catégorie d'avertissement comme paramètre.

@SuppressWarnings("deprecation")
public class RiddledWithWarnings {
    // several methods calling deprecated code here
}

@SuppressWarning("finally")
public boolean checkData() {
    // method calling return from within finally block
}

Il est préférable de limiter la portée de l'annotation autant que possible pour éviter la suppression des avertissements inattendus. Par exemple, en limitant la portée de l'annotation à une seule ligne:

ComplexAlgorithm algorithm = new ComplexAlgorithm();
@SuppressWarnings("deprecation") algoritm.slowUnthreadSafeMethod(); 
// we marked this method deprecated in an example above

@SuppressWarnings("unsafe") List<Integer> list = getUntypeSafeList(); 
// old library returns, non-generic List containing only integers

Les avertissements pris en charge par cette annotation peuvent varier d'un compilateur à l'autre. Seuls les avertissements unchecked et deprecation sont spécifiquement mentionnés dans le JLS. Les types d'avertissement non reconnus seront ignorés.

@SafeVarargs

En raison de l'effacement de type, la void method(T... t) sera convertie en void method(Object[] t) ce qui signifie que le compilateur n'est pas toujours en mesure de vérifier que l'utilisation de varargs est de type sécurisé. Par exemple:

private static <T> void generatesVarargsWarning(T... lists) {

Il existe des cas où l'utilisation est sûre, auquel cas vous pouvez annoter la méthode avec l'annotation SafeVarargs pour supprimer l'avertissement. Cela cache évidemment l'avertissement si votre utilisation est dangereuse aussi.

@Interface fonctionnelle

C'est une annotation facultative utilisée pour marquer une interface fonctionnelle. Cela amènera le compilateur à se plaindre s'il ne se conforme pas à la spécification de FunctionalInterface (possède une seule méthode abstraite)

@FunctionalInterface
public interface ITrade {
  public boolean check(Trade t);
}

@FunctionalInterface
public interface Predicate<T> {
  boolean test(T t);
}

Vérification des annotations d'exécution par réflexion

L'API de réflexion de Java permet au programmeur d'effectuer diverses vérifications et opérations sur les champs de classe, les méthodes et les annotations pendant l'exécution. Toutefois, pour qu'une annotation soit visible au moment de l'exécution, RetentionPolicy doit être remplacée par RUNTIME , comme illustré dans l'exemple ci-dessous:

@interface MyDefaultAnnotation {

}

@Retention(RetentionPolicy.RUNTIME)
@interface MyRuntimeVisibleAnnotation {

}

public class AnnotationAtRuntimeTest {

    @MyDefaultAnnotation
    static class RuntimeCheck1 {
    }
    
    @MyRuntimeVisibleAnnotation
    static class RuntimeCheck2 {
    }
    
    public static void main(String[] args) {
        Annotation[] annotationsByType = RuntimeCheck1.class.getAnnotations();
        Annotation[] annotationsByType2 = RuntimeCheck2.class.getAnnotations();

        System.out.println("default retention: " + Arrays.toString(annotationsByType));
        System.out.println("runtime retention: " + Arrays.toString(annotationsByType2));
    }
}

Définition des types d'annotation

Les types d'annotation sont définis avec @interface . Les paramètres sont définis de manière similaire aux méthodes d'une interface régulière.

@interface MyAnnotation {
    String param1();
    boolean param2();
    int[] param3();  // array parameter 
}

Les valeurs par défaut

@interface MyAnnotation {
    String param1() default "someValue";
    boolean param2() default true;
    int[] param3() default {};
}

Méta-annotations

Les méta-annotations sont des annotations pouvant être appliquées aux types d'annotation. Une méta-annotation prédéfinie spéciale définit comment les types d'annotation peuvent être utilisés.

@Cible

La méta-annotation @Target limite les types @Target l'annotation peut être appliquée.

@Target(ElementType.METHOD)
@interface MyAnnotation {
    // this annotation can only be applied to methods
}

Plusieurs valeurs peuvent être ajoutées en utilisant la notation de tableau, par exemple @Target({ElementType.FIELD, ElementType.TYPE})

Valeurs disponibles

ElementType cible exemple d'utilisation sur l'élément cible
ANNOTATION_TYPE types d'annotation
@Retention(RetentionPolicy.RUNTIME) 
@interface MyAnnotation
CONSTRUCTEUR constructeurs
@MyAnnotation
public MyClass() {}
CHAMP champs, constantes enum
@XmlAttribute
private int count;
VARIABLE LOCALE déclarations de variables à l'intérieur des méthodes
for (@LoopVariable int i = 0; i < 100; i++) {
@Unused
String resultVariable;
}
PAQUET package (dans package-info.java )
@Deprecated
package very.old;
MÉTHODE méthodes
@XmlElement
public int getCount() {...}
PARAMÈTRE paramètres de méthode / constructeur
public Rectangle(
@NamedArg("width") double width,
@NamedArg("height") double height) {
...
}
TYPE classes, interfaces, énumérations
@XmlRootElement
public class Report {}
Java SE 8
ElementType cible exemple d'utilisation sur l'élément cible
TYPE_PARAMETER Type de déclaration de paramètres
public <@MyAnnotation T> void f(T t) {}
TYPE_USE Utilisation d'un type
Object o = "42";
String s = (@MyAnnotation String) o;

@Rétention

La méta-annotation @Retention définit la visibilité de l'annotation pendant le processus de compilation ou d'exécution des applications. Par défaut, les annotations sont incluses dans les fichiers .class , mais ne sont pas visibles lors de l'exécution. Pour rendre une annotation accessible au moment de l'exécution, RetentionPolicy.RUNTIME doit être défini sur cette annotation.

@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
    // this annotation can be accessed with reflections at runtime
}

Valeurs disponibles

RetentionPolicy Effet
CLASSE L'annotation est disponible dans le fichier .class , mais pas à l'exécution
DUREE L'annotation est disponible au moment de l'exécution et est accessible via la réflexion
LA SOURCE L'annotation est disponible à la compilation, mais n'est pas ajoutée aux fichiers .class . L'annotation peut être utilisée, par exemple, par un processeur d'annotation.

@Documenté

La @Documented méta-annotation est utilisée pour marquer des annotations dont l' utilisation doit être documentée par des générateurs de documentation de l' API comme javadoc . Il n'a pas de valeurs. Avec @Documented , toutes les classes utilisant l'annotation le listeront sur leur page de documentation générée. Sans @Documented , il n'est pas possible de voir quelles classes utilisent l'annotation dans la documentation.

@Hérité

La méta-annotation @Inherited concerne les annotations appliquées aux classes. Il n'a pas de valeurs. Marquer une annotation comme @Inherited altère le fonctionnement de l'interrogation par annotation.

  • Pour une annotation non héritée, la requête examine uniquement la classe en cours d'examen.
  • Pour une annotation héritée, la requête vérifie également la chaîne de super-classe (récursivement) jusqu'à ce qu'une instance de l'annotation soit trouvée.

Notez que seules les super-classes sont interrogées: les annotations attachées aux interfaces dans la hiérarchie des classes seront ignorées.

@Repeatable

La méta-annotation @Repeatable été ajoutée à Java 8. Elle indique que plusieurs instances de l'annotation peuvent être attachées à la cible de l'annotation. Cette méta-annotation n'a aucune valeur.

Obtenir des valeurs d'annotation au moment de l'exécution

Vous pouvez extraire les propriétés actuelles de l'annotation en utilisant Reflection pour récupérer la méthode ou le champ ou la classe à laquelle une annotation est appliquée, puis extraire les propriétés souhaitées.

@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
    String key() default "foo";
    String value() default "bar";
}


class AnnotationExample {
    // Put the Annotation on the method, but leave the defaults
    @MyAnnotation
    public void testDefaults() throws Exception {
        // Using reflection, get the public method "testDefaults", which is this method with no args
        Method method = AnnotationExample.class.getMethod("testDefaults", null);

        // Fetch the Annotation that is of type MyAnnotation from the Method
        MyAnnotation annotation = (MyAnnotation)method.getAnnotation(MyAnnotation.class);

        // Print out the settings of the Annotation
        print(annotation);
    }

    //Put the Annotation on the method, but override the settings
    @MyAnnotation(key="baz", value="buzz")
    public void testValues() throws Exception {
        // Using reflection, get the public method "testValues", which is this method with no args
        Method method = AnnotationExample.class.getMethod("testValues", null);

        // Fetch the Annotation that is of type MyAnnotation from the Method
        MyAnnotation annotation = (MyAnnotation)method.getAnnotation(MyAnnotation.class);

        // Print out the settings of the Annotation
        print(annotation);
    }

    public void print(MyAnnotation annotation) {
        // Fetch the MyAnnotation 'key' & 'value' properties, and print them out 
        System.out.println(annotation.key() + " = " + annotation.value());
    }

    public static void main(String[] args) {
        AnnotationExample example = new AnnotationExample();
        try {
            example.testDefaults();
            example.testValues();
        } catch( Exception e ) {
            // Shouldn't throw any Exceptions
            System.err.println("Exception [" + e.getClass().getName() + "] - " + e.getMessage());
            e.printStackTrace(System.err);
        }
    }
}

La sortie sera

foo = bar
baz = buzz

Annotations répétées

Jusqu'à Java 8, deux instances de la même annotation ne pouvaient pas être appliquées à un seul élément. La solution de contournement standard consistait à utiliser une annotation de conteneur contenant un tableau d'une autre annotation:

// Author.java
@Retention(RetentionPolicy.RUNTIME)
public @interface Author {
    String value();
}

// Authors.java
@Retention(RetentionPolicy.RUNTIME)
public @interface Authors {
    Author[] value();
}

// Test.java
@Authors({
    @Author("Mary"),
    @Author("Sam")
})
public class Test {
    public static void main(String[] args) {
        Author[] authors = Test.class.getAnnotation(Authors.class).value();
        for (Author author : authors) {
            System.out.println(author.value());
            // Output:
            // Mary
            // Sam
        }
    }
}
Java SE 8

Java 8 fournit un moyen plus propre et plus transparent d'utiliser les annotations de conteneur, en utilisant l'annotation @Repeatable . Tout d'abord, nous ajoutons ceci à la classe Author :

@Repeatable(Authors.class)

Ceci indique à Java de traiter plusieurs annotations @Author comme si elles étaient entourées par le conteneur @Authors . Nous pouvons également utiliser Class.getAnnotationsByType() pour accéder au tableau @Author par sa propre classe, plutôt que par son conteneur:

@Author("Mary")
@Author("Sam")
public class Test {
    public static void main(String[] args) {
        Author[] authors = Test.class.getAnnotationsByType(Author.class);
        for (Author author : authors) {
            System.out.println(author.value());
            // Output:
            // Mary
            // Sam
        }
    }
}

Annotations héritées

Par défaut, les annotations de classe ne s'appliquent pas aux types qui les étendent. Cela peut être modifié en ajoutant l'annotation @Inherited à la définition d'annotation

Exemple

Considérez les 2 annotations suivantes:

@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface InheritedAnnotationType {
}

et

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface UninheritedAnnotationType {
}

Si trois classes sont annotées comme ceci:

@UninheritedAnnotationType
class A {
}

@InheritedAnnotationType
class B extends A {
}

class C extends B {
}

exécuter ce code

System.out.println(new A().getClass().getAnnotation(InheritedAnnotationType.class));
System.out.println(new B().getClass().getAnnotation(InheritedAnnotationType.class));
System.out.println(new C().getClass().getAnnotation(InheritedAnnotationType.class));
System.out.println("_________________________________");
System.out.println(new A().getClass().getAnnotation(UninheritedAnnotationType.class));
System.out.println(new B().getClass().getAnnotation(UninheritedAnnotationType.class));
System.out.println(new C().getClass().getAnnotation(UninheritedAnnotationType.class));

imprimera un résultat similaire à celui-ci (selon les paquets de l'annotation):

null
@InheritedAnnotationType()
@InheritedAnnotationType()
_________________________________
@UninheritedAnnotationType()
null
null

Notez que les annotations ne peuvent être héritées que des classes, pas des interfaces.

Compiler le traitement du temps à l'aide du processeur d'annotations

Cet exemple montre comment effectuer la vérification du temps de compilation d'un élément annoté.

L'annotation

L'annotation @Setter est un marqueur pouvant être appliqué aux méthodes. L'annotation sera supprimée lors de la compilation et ne sera plus disponible par la suite.

package annotation;

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

@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.METHOD)
public @interface Setter {
}

Le processeur d'annotation

La classe SetterProcessor est utilisée par le compilateur pour traiter les annotations. Il vérifie si les méthodes annotées avec l'annotation @Setter sont public , static méthodes non static avec un nom commençant par set et ayant une lettre majuscule comme 4ème lettre. Si l'une de ces conditions n'est pas remplie, une erreur est écrite dans le Messager . Le compilateur écrit ceci dans stderr, mais d'autres outils pourraient utiliser ces informations différemment. Par exemple, l'EDI NetBeans permet à l'utilisateur de spécifier des processeurs d'annotation utilisés pour afficher les messages d'erreur dans l'éditeur.

package annotation.processor;

import annotation.Setter;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;

@SupportedAnnotationTypes({"annotation.Setter"})
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class SetterProcessor extends AbstractProcessor {

    private Messager messager;

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        // get elements annotated with the @Setter annotation
        Set<? extends Element> annotatedElements = roundEnv.getElementsAnnotatedWith(Setter.class);

        for (Element element : annotatedElements) {
            if (element.getKind() == ElementKind.METHOD) {
                // only handle methods as targets
                checkMethod((ExecutableElement) element);
            }
        }

        // don't claim annotations to allow other processors to process them
        return false;
    }

    private void checkMethod(ExecutableElement method) {
        // check for valid name
        String name = method.getSimpleName().toString();
        if (!name.startsWith("set")) {
            printError(method, "setter name must start with \"set\"");
        } else if (name.length() == 3) {
            printError(method, "the method name must contain more than just \"set\"");
        } else if (Character.isLowerCase(name.charAt(3))) {
            if (method.getParameters().size() != 1) {
                printError(method, "character following \"set\" must be upper case");
            }
        }

        // check, if setter is public
        if (!method.getModifiers().contains(Modifier.PUBLIC)) {
            printError(method, "setter must be public");
        }

        // check, if method is static
        if (method.getModifiers().contains(Modifier.STATIC)) {
            printError(method, "setter must not be static");
        }
    }

    private void printError(Element element, String message) {
        messager.printMessage(Diagnostic.Kind.ERROR, message, element);
    }

    @Override
    public void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);

        // get messager for printing errors
        messager = processingEnvironment.getMessager();
    }

}

Emballage

Pour être appliqué par le compilateur, le processeur d'annotation doit être mis à la disposition du SPI (voir ServiceLoader ).

Pour ce faire, un fichier texte META-INF/services/javax.annotation.processing.Processor doit être ajouté au fichier jar contenant le processeur d’annotation et l’annotation en plus des autres fichiers. Le fichier doit inclure le nom complet du processeur d’annotation, c’est-à-dire qu’il doit ressembler à ceci:

annotation.processor.SetterProcessor

Nous supposerons que le fichier jar s'appelle AnnotationProcessor.jar ci-dessous.

Exemple de classe annotée

La classe suivante est un exemple de classe dans le package par défaut, les annotations étant appliquées aux éléments corrects conformément à la stratégie de rétention. Cependant, seul le processeur d'annotation considère uniquement la seconde méthode comme une cible d'annotation valide.

import annotation.Setter;

public class AnnotationProcessorTest {
    
    @Setter
    private void setValue(String value) {}

    @Setter
    public void setString(String value) {}
    
    @Setter
    public static void main(String[] args) {}
    
}

Utilisation du processeur d'annotations avec javac

Si le processeur d'annotations est détecté à l'aide du SPI, il est automatiquement utilisé pour traiter les éléments annotés. Par exemple, compiler la classe AnnotationProcessorTest utilisant

javac -cp AnnotationProcessor.jar AnnotationProcessorTest.java

donne la sortie suivante

AnnotationProcessorTest.java:6: error: setter must be public
    private void setValue(String value) {}
                 ^
AnnotationProcessorTest.java:12: error: setter name must start with "set"
    public static void main(String[] args) {}
                       ^
2 errors

au lieu de compiler normalement. Aucun fichier .class n'est créé.

Cela pourrait être évité en spécifiant l'option -proc:none pour javac . Vous pouvez également renoncer à la compilation habituelle en spécifiant -proc:only place.

Intégration IDE

Netbeans

Les processeurs d'annotation peuvent être utilisés dans l'éditeur NetBeans. Pour ce faire, le processeur d'annotations doit être spécifié dans les paramètres du projet:

  1. allez dans Project Properties > Build > Compiling

  2. ajouter des coches pour Enable Annotation Processing et Enable Annotation Processing in Editor

  3. cliquez sur Add regard de la liste des processeurs d'annotations

  4. Dans la fenêtre qui apparaît, entrez le nom de classe complet du processeur d’annotation et cliquez sur Ok .

Résultat

Fenêtre de l'éditeur avec un message d'erreur personnalisé

L'idée des annotations

La spécification de langage Java décrit les annotations comme suit:

Une annotation est un marqueur qui associe des informations à une construction de programme, mais n'a aucun effet au moment de l'exécution.

Les annotations peuvent apparaître avant les types ou les déclarations. Il est possible qu'ils apparaissent dans un endroit où ils pourraient s'appliquer à la fois à un type ou à une déclaration.
Ce à quoi s'applique exactement une annotation est régi par la "méta-annotation" @Target . Voir "Définition des types d'annotation" pour plus d'informations.

Les annotations sont utilisées à des fins multiples. Les cadres tels que Spring et Spring-MVC utilisent des annotations pour définir où les dépendances doivent être injectées ou où les requêtes doivent être acheminées.

D'autres frameworks utilisent des annotations pour la génération de code. Lombok et JPA sont des exemples principaux, qui utilisent des annotations pour générer du code Java (et SQL).

Ce sujet vise à fournir un aperçu complet de:

  • Comment définir vos propres annotations?

  • Quelles sont les annotations fournies par le langage Java?

  • Comment les annotations sont-elles utilisées dans la pratique?

Annotations pour 'this' et paramètres du récepteur

Lorsque les annotations Java ont été introduites pour la première fois, aucune disposition ne permettait d'annoter la cible d'une méthode d'instance ou le paramètre constructeur caché d'un constructeur de classes internes. Cela a été corrigé dans Java 8 avec l'ajout des déclarations de paramètres du récepteur ; voir JLS 8.4.1 .

Le paramètre récepteur est un périphérique syntaxique facultatif pour une méthode d'instance ou un constructeur de classe interne. Pour une méthode d'instance, le paramètre récepteur représente l'objet pour lequel la méthode est appelée. Pour un constructeur de classe interne, le paramètre receiver représente l'instance englobante immédiate de l'objet nouvellement construit. De toute façon, le paramètre récepteur existe uniquement pour permettre au type de l'objet représenté d'être désigné dans le code source, de sorte que le type puisse être annoté. Le paramètre du récepteur n'est pas un paramètre formel; plus précisément, il ne s’agit pas d’une déclaration de variable quelconque (§4.12.3), elle n’est jamais liée à une valeur passée en argument dans une expression d’invocation de méthode ou une expression de création d’instance de classe qualifiée, et elle n’a aucun effet sur temps d'exécution

L'exemple suivant illustre la syntaxe des deux types de paramètres du récepteur:

public class Outer {
    public class Inner {
        public Inner (Outer this) {
           // ...
        }
        public void doIt(Inner this) {
           // ...
        }
    }
}

Les paramètres du récepteur ont pour seul objectif d’ajouter des annotations. Par exemple, vous pouvez avoir une annotation personnalisée @IsOpen dont le but est d'affirmer qu'un objet Closeable n'a pas été fermé lorsqu'une méthode est appelée. Par exemple:

public class MyResource extends Closeable {
    public void update(@IsOpen MyResource this, int value) {
        // ...
    }

    public void close() {
        // ...
    }
}

À un @IsOpen niveau, l'annotation @IsOpen sur this @IsOpen pourrait simplement servir de documentation. Cependant, nous pourrions potentiellement faire plus. Par exemple:

  • Un processeur d’annotations peut insérer un contrôle d’exécution indiquant this n’est pas fermé lorsque la update à update est appelée.
  • Un vérificateur de code peut effectuer une analyse de code statique pour trouver des cas où this pourrait être fermé lorsque la update à update est appelée.

Ajouter plusieurs valeurs d'annotation

Un paramètre Annotation peut accepter plusieurs valeurs s'il est défini en tant que tableau. Par exemple, l'annotation standard @SuppressWarnings est définie comme suit:

public @interface SuppressWarnings {
    String[] value();
}

Le paramètre value est un tableau de chaînes. Vous pouvez définir plusieurs valeurs en utilisant une notation similaire aux initialiseurs de tableau:

@SuppressWarnings({"unused"})
@SuppressWarnings({"unused", "javadoc"})

Si vous ne devez définir qu'une seule valeur, les parenthèses peuvent être omises:

@SuppressWarnings("unused") 


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow