Java Language
annotazioni
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 | |
COSTRUTTORE | costruttori | |
CAMPO | campi, costanti enum | |
LOCAL_VARIABLE | dichiarazioni variabili all'interno dei metodi | |
PACCHETTO | pacchetto (in package-info.java ) | |
METODO | metodi | |
PARAMETRO | parametri metodo / costruttore | |
GENERE | classi, interfacce, enumerazioni | |
ElementType | bersaglio | esempio di utilizzo sull'elemento target |
---|---|---|
TYPE_PARAMETER | Digitare dichiarazioni dei parametri | |
TYPE_USE | Uso di un tipo | |
@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 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:
vai su
Project Properties
>Build
>Compiling
aggiungere segni di spunta per
Enable Annotation Processing
eEnable Annotation Processing in Editor
fare clic su
Add
accanto all'elenco dei processori di annotazionenel popup che appare inserisci il nome completo della classe del processore di annotazione e fai clic su
Ok
.
Risultato
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")