Ricerca…


introduzione

In Java, un'annotazione è una forma di metadati sintattici che possono essere aggiunti al codice sorgente Java. Fornisce dati su un programma che non fa parte del programma stesso. Le annotazioni non hanno alcun effetto diretto sul funzionamento del codice annotato. Classi, metodi, variabili, parametri e pacchetti possono essere annotati.

Sintassi

  • @AnnotationName // 'Annotazione marcatore' (nessun parametro)
  • @AnnotationName (someValue) // imposta il parametro con il nome 'valore'
  • @AnnotationName (param1 = value1) // parametro denominato
  • @AnnotationName (param1 = value1, param2 = value2) // più parametri con nome
  • @AnnotationName (param1 = {1, 2, 3}) // parametro con nome named
  • @AnnotationName ({value1}) // array con singolo elemento come parametro con il nome 'valore'

Osservazioni

Tipi di parametri

Solo le espressioni costanti dei seguenti tipi sono consentite per i parametri, così come gli array di questi tipi:

  • String
  • Class
  • tipi primitivi
  • Tipi di Enum
  • Tipi di annotazione

Annotazioni incorporate

La Standard Edition di Java viene fornita con alcune annotazioni predefinite. Non è necessario definirli da soli e puoi utilizzarli immediatamente. Permettono al compilatore di abilitare alcuni controlli fondamentali su metodi, classi e codici.

@Oltrepassare

Questa annotazione si applica a un metodo e afferma che questo metodo deve sovrascrivere il metodo di una superclasse o implementare una definizione di metodo di una superclasse astratta. Se questa annotazione viene utilizzata con qualsiasi altro tipo di metodo, il compilatore genererà un errore.

Superclasse concreta

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 astratta

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

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

Non funziona

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);
    }
}

Lo scopo principale è catturare l'errore di digitazione, in cui si pensa di ignorare un metodo, ma in realtà ne sta definendo uno nuovo.

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");
    }
}

Nota che il significato di @Override è cambiato nel tempo:

  • In Java 5, significava che il metodo annotato doveva sovrascrivere un metodo non astratto dichiarato nella catena della superclasse.
  • Da Java 6 in poi, è anche soddisfatto se il metodo annotato implementa un metodo astratto dichiarato nella gerarchia superclasse / interfaccia delle classi.

(Ciò può causare occasionalmente problemi quando si esegue il back-porting del codice su Java 5.)

@deprecated

Questo contrassegna il metodo come deprecato. Ci possono essere diverse ragioni per questo:

  • l'API è difettosa e non è pratico da risolvere,

  • l'utilizzo dell'API può causare errori,

  • l'API è stata sostituita da un'altra API,

  • l'API è obsoleta,

  • l'API è sperimentale ed è soggetta a modifiche incompatibili,

  • o qualsiasi combinazione di quanto sopra.

Il motivo specifico della deprecazione si trova di solito nella documentazione dell'API.


L'annotazione farà sì che il compilatore emetta un errore se lo si utilizza. Gli IDE possono anche evidenziare questo metodo in qualche modo come deprecato

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

@SuppressWarnings

In quasi tutti i casi, quando il compilatore emette un avviso, l'azione più appropriata è quella di correggere la causa. In alcuni casi (codice generics che utilizza un codice di pre-generica non sicuro, ad esempio) questo potrebbe non essere possibile ed è meglio sopprimere quegli avvertimenti che ci si aspetta e non è possibile correggere, in modo da poter vedere più chiaramente gli avvertimenti inattesi.

Questa annotazione può essere applicata a un'intera classe, metodo o linea. Prende la categoria di avvertimento come parametro.

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

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

È preferibile limitare il più possibile l'ambito dell'annotazione, per evitare che vengano eliminati anche gli avvisi imprevisti. Ad esempio, confinando l'ambito dell'annotazione su una singola riga:

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

Gli avvertimenti supportati da questa annotazione possono variare da compilatore a compilatore. Solo gli avvertimenti unchecked e di deprecation sono specificatamente menzionati nel JLS. I tipi di avvertimento non riconosciuti verranno ignorati.

@SafeVarargs

A causa della cancellazione dei tipi, il void method(T... t) verrà convertito in void method(Object[] t) il che significa che il compilatore non è sempre in grado di verificare che l'uso di varargs sia sicuro per il tipo. Per esempio:

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

Esistono casi in cui l'utilizzo è sicuro, nel qual caso è possibile annotare il metodo con l'annotazione di SafeVarargs per sopprimere l'avviso. Ovviamente questo nasconde l'avviso se il tuo uso non è sicuro.

@FunctionalInterface

Questa è un'annotazione opzionale utilizzata per contrassegnare una FunctionalInterface. Fa sì che il compilatore si lamenti se non è conforme alle specifiche di FunctionalInterface (ha un singolo metodo astratto)

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

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

Controlli delle annotazioni di runtime tramite riflessione

L'API Reflection di Java consente al programmatore di eseguire vari controlli e operazioni su campi di classi, metodi e annotazioni durante il runtime. Tuttavia, affinché un'annotazione sia visibile al momento dell'esecuzione, RetentionPolicy deve essere modificato in RUNTIME , come illustrato nell'esempio seguente:

@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));
    }
}

Definizione dei tipi di annotazione

I tipi di annotazione sono definiti con @interface . I parametri sono definiti come i metodi di un'interfaccia regolare.

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

Valori standard

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

Meta-Annotazioni

Le meta-annotazioni sono annotazioni che possono essere applicate ai tipi di annotazione. Una speciale meta-annotazione predefinita definisce come possono essere usati i tipi di annotazione.

@Bersaglio

La meta-annotazione @Target limita i tipi a cui può essere applicata l'annotazione.

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

È possibile aggiungere più valori utilizzando la notazione array, ad esempio @Target({ElementType.FIELD, ElementType.TYPE})

Valori disponibili

ElementType bersaglio esempio di utilizzo sull'elemento target
ANNOTATION_TYPE tipi di annotazione
@Retention(RetentionPolicy.RUNTIME) 
@interface MyAnnotation
COSTRUTTORE costruttori
@MyAnnotation
public MyClass() {}
CAMPO campi, costanti enum
@XmlAttribute
private int count;
LOCAL_VARIABLE dichiarazioni variabili all'interno dei metodi
for (@LoopVariable int i = 0; i < 100; i++) {
@Unused
String resultVariable;
}
PACCHETTO pacchetto (in package-info.java )
@Deprecated
package very.old;
METODO metodi
@XmlElement
public int getCount() {...}
PARAMETRO parametri metodo / costruttore
public Rectangle(
@NamedArg("width") double width,
@NamedArg("height") double height) {
...
}
GENERE classi, interfacce, enumerazioni
@XmlRootElement
public class Report {}
Java SE 8
ElementType bersaglio esempio di utilizzo sull'elemento target
TYPE_PARAMETER Digitare dichiarazioni dei parametri
public <@MyAnnotation T> void f(T t) {}
TYPE_USE Uso di un tipo
Object o = "42";
String s = (@MyAnnotation String) o;

@Ritenzione

La meta-annotazione @Retention definisce la visibilità dell'annotazione durante il processo di compilazione delle applicazioni o l'esecuzione. Per impostazione predefinita, le annotazioni sono incluse nei file .class , ma non sono visibili in fase di runtime. Per rendere accessibile un'annotazione in fase di esecuzione, RetentionPolicy.RUNTIME deve essere impostato su tale annotazione.

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

Valori disponibili

RetentionPolicy Effetto
CLASSE L'annotazione è disponibile nel file .class , ma non in fase di runtime
DURATA L'annotazione è disponibile in runtime e si può accedere tramite riflessione
FONTE L'annotazione è disponibile in fase di compilazione, ma non aggiunta ai file .class . L'annotazione può essere utilizzata ad esempio da un processore di annotazione.

@Documented

La meta-annotazione @Documented viene utilizzata per contrassegnare annotazioni il cui utilizzo dovrebbe essere documentato da generatori di documentazione API come javadoc . Non ha valori. Con @Documented , tutte le classi che utilizzano l'annotazione lo elencheranno nella pagina della documentazione generata. Senza @Documented , non è possibile vedere quali classi utilizzano l'annotazione nella documentazione.

@Ereditato

La meta-annotazione @Inherited è pertinente alle annotazioni applicate alle classi. Non ha valori. Contrassegnare un'annotazione come @Inherited altera il modo in cui funziona la query di annotazione.

  • Per un'annotazione non ereditata, la query esamina solo la classe esaminata.
  • Per un'annotazione ereditata, la query controlla anche la catena super-classe (in modo ricorsivo) finché non viene trovata un'istanza dell'annotazione.

Si noti che vengono interrogate solo le super classi: eventuali annotazioni associate alle interfacce nella gerarchia delle classi verranno ignorate.

@Ripetibile

@Repeatable La meta-annotazione @Repeatable stata aggiunta in Java 8. Indica che più istanze dell'annotazione possono essere associate alla destinazione dell'annotazione. Questa meta-annotazione non ha valori.

Ottenere i valori di annotazione in fase di esecuzione

È possibile recuperare le proprietà correnti dell'Annotazione utilizzando Reflection per recuperare il metodo o campo o classe a cui è stata applicata un'annotazione e quindi recuperare le proprietà desiderate.

@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);
        }
    }
}

L'output sarà

foo = bar
baz = buzz

Ripetere le annotazioni

Fino a Java 8, due istanze della stessa annotazione non potevano essere applicate a un singolo elemento. La soluzione standard consisteva nell'utilizzare un'annotazione del contenitore contenente una serie di altre annotazioni:

// 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 fornisce un modo più pulito e più trasparente di utilizzare le annotazioni del contenitore, utilizzando l'annotazione @Repeatable . Per prima cosa aggiungiamo questo alla classe Author :

@Repeatable(Authors.class)

Ciò indica a Java di trattare più annotazioni @Author come se fossero circondate dal contenitore @Authors . Possiamo anche utilizzare Class.getAnnotationsByType() per accedere all'array @Author tramite la sua classe, anziché tramite il relativo contenitore:

@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
        }
    }
}

Annotazioni ereditate

Per impostazione predefinita, le annotazioni di classe non si applicano ai tipi che le estendono. Questo può essere modificato aggiungendo l'annotazione @Inherited alla definizione di annotazione

Esempio

Considera le seguenti 2 annotazioni:

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

e

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

Se tre classi sono annotate in questo modo:

@UninheritedAnnotationType
class A {
}

@InheritedAnnotationType
class B extends A {
}

class C extends B {
}

eseguendo questo codice

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));

stamperà un risultato simile a questo (a seconda dei pacchetti dell'annotazione):

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

Nota che le annotazioni possono essere ereditate solo dalle classi, non dalle interfacce.

Compilare l'elaborazione del tempo usando il processore di annotazione

Questo esempio dimostra come eseguire il controllo del tempo di compilazione di un elemento annotato.

L'annotazione

L'annotazione @Setter è un indicatore che può essere applicato ai metodi. L'annotazione verrà scartata durante la compilazione e non sarà disponibile successivamente.

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 {
}

Il processore di annotazione

La classe SetterProcessor viene utilizzata dal compilatore per elaborare le annotazioni. Controlla, se i metodi annotati con l'annotazione @Setter sono metodi public , non static con un nome che inizia con set e che ha una lettera maiuscola come quarta lettera. Se una di queste condizioni non viene soddisfatta, viene inviato un errore al Messager . Il compilatore scrive questo su stderr, ma altri strumenti potrebbero usare queste informazioni in modo diverso. Ad esempio, l'IDE NetBeans consente all'utente di specificare i processori di annotazione utilizzati per visualizzare i messaggi di errore nell'editor.

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();
    }

}

Confezione

Per essere applicato dal compilatore, il processore di annotazione deve essere reso disponibile per l'SPI (vedere ServiceLoader ).

Per fare ciò è necessario aggiungere un file di testo META-INF/services/javax.annotation.processing.Processor al file jar contenente il processore di annotazione e l'annotazione in aggiunta agli altri file. Il file deve includere il nome completo del processore di annotazione, ovvero dovrebbe apparire come questo

annotation.processor.SetterProcessor

Supponiamo che il file jar sia chiamato AnnotationProcessor.jar seguito.

Esempio di classe annotata

La classe seguente è una classe di esempio nel pacchetto predefinito con le annotazioni applicate agli elementi corretti in base al criterio di conservazione. Tuttavia, solo il processore di annotazione considera solo il secondo metodo un target di annotazione valido.

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) {}
    
}

Utilizzo del processore di annotazione con javac

Se il processore di annotazione viene rilevato utilizzando SPI, viene utilizzato automaticamente per elaborare gli elementi annotati. Ad esempio compilando la classe AnnotationProcessorTest utilizzando

javac -cp AnnotationProcessor.jar AnnotationProcessorTest.java

produce il seguente output

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

invece di compilare normalmente. Nessun file .class creato.

Questo potrebbe essere evitato specificando l'opzione -proc:none per javac . Puoi anche rinunciare alla solita compilazione specificando -proc:only invece.

Integrazione IDE

Netbeans

I processori di annotazione possono essere utilizzati nell'editor NetBeans. Per fare ciò è necessario specificare il processore di annotazione nelle impostazioni del progetto:

  1. vai su Project Properties > Build > Compiling

  2. aggiungere segni di spunta per Enable Annotation Processing e Enable Annotation Processing in Editor

  3. fare clic su Add accanto all'elenco dei processori di annotazione

  4. nel popup che appare inserisci il nome completo della classe del processore di annotazione e fai clic su Ok .

Risultato

Finestra dell'editor con messaggio di errore personalizzato

L'idea alla base di Annotations

La specifica del linguaggio Java descrive le annotazioni come segue:

Un'annotazione è un marcatore che associa informazioni con un costrutto di programma, ma non ha alcun effetto in fase di esecuzione.

Le annotazioni possono comparire prima dei tipi o delle dichiarazioni. È possibile che vengano visualizzati in un punto in cui potrebbero essere applicati sia a un tipo sia a una dichiarazione.
A che cosa si applica esattamente un'annotazione è governato dalla "meta-annotazione" @Target . Vedere "Definizione dei tipi di annotazione" per ulteriori informazioni.

Le annotazioni sono utilizzate per una moltitudine di scopi. I framework come Spring e Spring-MVC fanno uso di annotazioni per definire dove devono essere iniettate le dipendenze o dove devono essere instradate le richieste.

Altri framework usano annotazioni per la generazione del codice. Lombok e JPA sono esempi primari, che usano annotazioni per generare codice Java (e SQL).

Questo argomento mira a fornire una panoramica completa di:

  • Come definire le tue annotazioni?

  • Quali annotazioni fornisce la lingua Java?

  • Come vengono utilizzate le annotazioni nella pratica?

Annotazioni per "questo" e parametri del ricevitore

Quando sono state introdotte per la prima volta le annotazioni Java, non era prevista la possibilità di annotare la destinazione di un metodo di istanza o il parametro del costruttore nascosto per un costruttore di classi interne. Questo è stato risolto in Java 8 con l'aggiunta delle dichiarazioni dei parametri del ricevitore ; vedi JLS 8.4.1 .

Il parametro receiver è un dispositivo sintattico opzionale per un metodo di istanza o un costruttore di una classe interna. Per un metodo di istanza, il parametro receiver rappresenta l'oggetto per cui viene invocato il metodo. Per il costruttore di una classe interna, il parametro ricevente rappresenta l'istanza immediatamente allegata dell'oggetto appena costruito. In entrambi i casi, il parametro ricevitore esiste unicamente per consentire al tipo dell'oggetto rappresentato di essere indicato nel codice sorgente, in modo che il tipo possa essere annotato. Il parametro del ricevitore non è un parametro formale; più precisamente, non è una dichiarazione di alcun tipo di variabile (§4.12.3), non è mai vincolata a nessun valore passato come argomento in un'espressione di chiamata di metodo o espressione di creazione di istanza di classe qualificata e non ha alcun effetto su tempo di esecuzione.

L'esempio seguente illustra la sintassi per entrambi i tipi di parametro del ricevitore:

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

L'unico scopo dei parametri del ricevitore è consentire l'aggiunta di annotazioni. Ad esempio, potresti avere un'annotazione personalizzata @IsOpen cui scopo è quello di affermare che un oggetto Closeable non è stato chiuso quando viene chiamato un metodo. Per esempio:

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

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

Ad un livello, l'annotazione @IsOpen su this potrebbe semplicemente servire come documentazione. Tuttavia, potremmo potenzialmente fare di più. Per esempio:

  • Un processore di annotazione potrebbe inserire un runtime per verificare che this non sia in stato chiuso quando viene chiamato l' update .
  • Un controllo del codice può eseguire un'analisi del codice statico per trovare casi in cui this potrebbe essere chiuso quando viene chiamato l' update .

Aggiungi più valori di annotazione

Un parametro Annotation può accettare più valori se è definito come array. Ad esempio, l'annotazione standard @SuppressWarnings è definita in questo modo:

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

Il parametro value è un array di stringhe. È possibile impostare più valori utilizzando una notazione simile agli inizializzatori di array:

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

Se hai solo bisogno di impostare un valore singolo, le parentesi possono essere omesse:

@SuppressWarnings("unused") 


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow