Java Language
aantekeningen
Zoeken…
Invoering
In Java is een annotatie een vorm van syntactische metadata die kan worden toegevoegd aan de Java-broncode. Het biedt gegevens over een programma dat geen deel uitmaakt van het programma zelf. Annotaties hebben geen direct effect op de werking van de code die ze annoteren. Klassen, methoden, variabelen, parameters en pakketten mogen worden geannoteerd.
Syntaxis
- @AnnotationName // 'Marker annotation' (geen parameters)
- @AnnotationName (someValue) // sets parameter met de naam 'value'
- @AnnotationName (param1 = waarde1) // benoemde parameter
- @AnnotationName (param1 = waarde1, param2 = waarde2) // meerdere benoemde parameters
- @AnnotationName (param1 = {1, 2, 3}) // benoemd array parameter
- @AnnotationName ({value1}) // array met één element als parameter met de naam 'value'
Opmerkingen
Parameter types
Alleen constante expressies van de volgende typen zijn toegestaan voor parameters, evenals arrays van deze typen:
-
String
-
Class
- primitieve typen
- Enum-typen
- Annotatietypen
Ingebouwde annotaties
De standaardeditie van Java wordt geleverd met vooraf gedefinieerde annotaties. U hoeft ze niet zelf te definiëren en u kunt ze meteen gebruiken. Hiermee kan de compiler een fundamentele controle van methoden, klassen en code mogelijk maken.
@ Override
Deze annotatie is van toepassing op een methode en zegt dat deze methode de definitie van een superklasse moet overschrijven of een definitie van een abstracte superklasse moet implementeren. Als deze annotatie met een andere methode wordt gebruikt, geeft de compiler een foutmelding.
Concrete superklasse
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");
}
}
Abstracte klasse
abstract class Animal {
public abstract void makeNoise();
}
class Dog extends Animal {
// Fine
@Override
public void makeNoise() {
System.out.prinln("Woof");
}
}
Werkt niet
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);
}
}
Het belangrijkste doel is om typefouten te ontdekken, waarbij u denkt dat u een methode overschrijft, maar eigenlijk een nieuwe methode definieert.
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");
}
}
Merk op dat de betekenis van @Override
in de loop van de tijd is veranderd:
- In Java 5 betekende dit dat de geannoteerde methode een niet-abstracte methode moest overschrijven die in de superklasse-keten werd vermeld.
- Vanaf Java 6 is het ook tevreden als de geannoteerde methode een abstracte methode implementeert die is gedeclareerd in de klassen superclass / interfacehiërarchie.
(Dit kan soms problemen veroorzaken bij het back-porten van code naar Java 5.)
@Verouderd
Dit markeert de methode als verouderd. Hier kunnen verschillende redenen voor zijn:
de API is gebrekkig en is onpraktisch om op te lossen,
gebruik van de API leidt waarschijnlijk tot fouten,
de API is vervangen door een andere API,
de API is verouderd,
de API is experimenteel en is onderhevig aan incompatibele wijzigingen,
of een combinatie van bovenstaande.
De specifieke reden voor afschrijving is meestal te vinden in de documentatie van de API.
De annotatie veroorzaakt dat de compiler een foutmelding geeft als u deze gebruikt. IDE's kunnen deze methode ook op de een of andere manier als verouderd markeren
class ComplexAlgorithm {
@Deprecated
public void oldSlowUnthreadSafeMethod() {
// stuff here
}
public void quickThreadSafeMethod() {
// client code should use this instead
}
}
@SuppressWarnings
In bijna alle gevallen, wanneer de compiler een waarschuwing geeft, is de meest geschikte actie om de oorzaak te verhelpen. In sommige gevallen (Generics code met bijvoorbeeld untype-safe pre-generics code) is dit misschien niet mogelijk en is het beter om de waarschuwingen te onderdrukken die u verwacht en niet kunt verhelpen, zodat u duidelijker onverwachte waarschuwingen kunt zien.
Deze annotatie kan worden toegepast op een hele klasse, methode of lijn. Het neemt de categorie van waarschuwing als een parameter.
@SuppressWarnings("deprecation")
public class RiddledWithWarnings {
// several methods calling deprecated code here
}
@SuppressWarning("finally")
public boolean checkData() {
// method calling return from within finally block
}
Het is beter om de reikwijdte van de annotatie zoveel mogelijk te beperken, om te voorkomen dat onverwachte waarschuwingen ook worden onderdrukt. Bijvoorbeeld door de reikwijdte van de annotatie te beperken tot één regel:
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
De waarschuwingen die door deze annotatie worden ondersteund, kunnen variëren van compiler tot compiler. Alleen de unchecked
en deprecation
worden specifiek vermeld in de JLS. Niet-herkende waarschuwingstypen worden genegeerd.
@SafeVarargs
Vanwege het wissen van het type, wordt de void method(T... t)
geconverteerd naar de void method(Object[] t)
wat betekent dat de compiler niet altijd in staat is te verifiëren dat het gebruik van varargs type-veilig is. Bijvoorbeeld:
private static <T> void generatesVarargsWarning(T... lists) {
Er zijn gevallen waarin het gebruik veilig is, in welk geval u de methode kunt annoteren met de SafeVarargs
annotatie om de waarschuwing te onderdrukken. Dit verbergt duidelijk de waarschuwing als uw gebruik ook onveilig is.
@FunctionalInterface
Dit is een optionele annotatie die wordt gebruikt om een functionele interface te markeren. Hierdoor zal de compiler klagen als deze niet voldoet aan de FunctionalInterface-specificatie (heeft een enkele abstracte methode)
@FunctionalInterface
public interface ITrade {
public boolean check(Trade t);
}
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
Controle van runtime-annotaties via reflectie
Met Java's Reflection API kan de programmeur tijdens runtime verschillende controles en bewerkingen uitvoeren op klassenvelden, methoden en annotaties. Om een annotatie tijdens runtime helemaal zichtbaar te maken, moet de RetentionPolicy
echter worden gewijzigd in RUNTIME
, zoals aangetoond in het onderstaande voorbeeld:
@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));
}
}
Aantekeningstypen definiëren
Annotatietypen worden gedefinieerd met @interface
. Parameters zijn vergelijkbaar met methoden van een reguliere interface.
@interface MyAnnotation {
String param1();
boolean param2();
int[] param3(); // array parameter
}
Standaard waarden
@interface MyAnnotation {
String param1() default "someValue";
boolean param2() default true;
int[] param3() default {};
}
Meta-Aantekeningen
Meta-annotaties zijn annotaties die kunnen worden toegepast op annotatietypen. Speciale vooraf gedefinieerde meta-annotaties definiëren hoe annotatietypen kunnen worden gebruikt.
@Doelwit
De meta-annotatie @Target
beperkt de typen waarop de annotatie kan worden toegepast.
@Target(ElementType.METHOD)
@interface MyAnnotation {
// this annotation can only be applied to methods
}
Meerdere waarden kunnen worden toegevoegd met behulp van matrixnotatie, bijv. @Target({ElementType.FIELD, ElementType.TYPE})
Beschikbare waarden
ElementType | doelwit | voorbeeld gebruik op doelelement |
---|---|---|
ANNOTATION_TYPE | annotatietypen | |
CONSTRUCTOR | constructeurs | |
VELD | velden, enum-constanten | |
LOCAL_VARIABLE | variabele verklaringen binnen methoden | |
PAKKET | pakket (in package-info.java ) | |
METHODE | methoden | |
PARAMETER | methode / constructorparameters | |
TYPE | klassen, interfaces, enums | |
ElementType | doelwit | voorbeeld gebruik op doelelement |
---|---|---|
TYPE_PARAMETER | Typ parameter verklaringen | |
TYPE_USE | Gebruik van een type | |
@Retention
De meta-annotatie @Retention
definieert de annotatiezichtbaarheid tijdens het compilatieproces of de uitvoering van de toepassing. Standaard zijn annotaties opgenomen in .class
bestanden, maar zijn niet zichtbaar tijdens runtime. Om een annotatie tijdens runtime toegankelijk te maken, moet RetentionPolicy.RUNTIME
op die annotatie worden ingesteld.
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
// this annotation can be accessed with reflections at runtime
}
Beschikbare waarden
RetentionPolicy | Effect |
---|---|
KLASSE | De annotatie is beschikbaar in het .class bestand, maar niet tijdens runtime |
RUNTIME | De annotatie is beschikbaar tijdens runtime en is toegankelijk via reflectie |
BRON | De annotatie is beschikbaar tijdens het compileren, maar niet toegevoegd aan de .class bestanden. De annotatie kan bijvoorbeeld worden gebruikt door een annotatieprocessor. |
@Documented
De @Documented
meta-annotatie wordt gebruikt om annotaties te markeren waarvan het gebruik moet worden gedocumenteerd door API-documentatie-generators zoals javadoc . Het heeft geen waarden. Met @Documented
alle klassen die de annotatie gebruiken deze op hun gegenereerde documentatiepagina. Zonder @Documented
is het niet mogelijk om te zien welke klassen de annotatie in de documentatie gebruiken.
@Inherited
De @Inherited
meta-annotatie is relevant voor annotaties die worden toegepast op klassen. Het heeft geen waarden. Een annotatie markeren als @Inherited
verandert de manier waarop annotatiequery's werken.
- Voor een niet-geërfde annotatie onderzoekt de query alleen de klasse die wordt onderzocht.
- Voor een geërfde annotatie controleert de query ook de superklasse-keten (recursief) totdat een exemplaar van de annotatie wordt gevonden.
Merk op dat alleen de superklassen worden opgevraagd: annotaties die zijn gekoppeld aan interfaces in de klassenhiërarchie worden genegeerd.
@Repeatable
De @Repeatable
meta-annotatie is toegevoegd in Java 8. Het geeft aan dat meerdere exemplaren van de annotatie aan het doel van de annotatie kunnen worden gekoppeld. Deze meta-annotatie heeft geen waarden.
Annotatiewaarden verkrijgen tijdens runtime
U kunt de huidige eigenschappen van de annotatie ophalen door Reflectie te gebruiken om de methode of het veld of de klasse op te halen waarop een annotatie is toegepast en vervolgens de gewenste eigenschappen op te halen.
@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);
}
}
}
De output zal zijn
foo = bar
baz = buzz
Herhalende annotaties
Tot Java 8 konden twee instanties van dezelfde annotatie niet op een enkel element worden toegepast. De standaardoplossing was het gebruik van een containerannotatie met een reeks andere annotaties:
// 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 biedt een schonere, transparantere manier om containerannotaties te gebruiken, met behulp van de @Repeatable
annotatie. Eerst voegen we dit toe aan de klasse Author
:
@Repeatable(Authors.class)
Dit vertelt Java om meerdere @Author
annotaties te behandelen alsof ze omringd zijn door de container @Authors
. We kunnen ook Class.getAnnotationsByType()
om toegang te krijgen tot de @Author
array door zijn eigen klasse, in plaats van via zijn container:
@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
}
}
}
Overgenomen annotaties
Standaard zijn annotaties van klasse niet van toepassing op typen die deze uitbreiden. Dit kan worden gewijzigd door de @Inherited
annotatie toe te voegen aan de annotatiedefinitie
Voorbeeld
Overweeg de volgende 2 annotaties:
@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface InheritedAnnotationType {
}
en
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface UninheritedAnnotationType {
}
Als drie klassen als volgt zijn geannoteerd:
@UninheritedAnnotationType
class A {
}
@InheritedAnnotationType
class B extends A {
}
class C extends B {
}
deze code uitvoeren
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));
zal een vergelijkbaar resultaat afdrukken als dit (afhankelijk van de pakketten van de annotatie):
null
@InheritedAnnotationType()
@InheritedAnnotationType()
_________________________________
@UninheritedAnnotationType()
null
null
Merk op dat annotaties alleen kunnen worden overgenomen van klassen, niet van interfaces.
Compileer tijdverwerking met behulp van annotatieprocessor
Dit voorbeeld laat zien hoe compileer tijdcontrole van een geannoteerd element uit te voeren.
De annotatie
De @Setter
annotatie is een markering die op methoden kan worden toegepast. De annotatie wordt verwijderd tijdens het compileren en is daarna niet meer beschikbaar.
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 {
}
De annotatieprocessor
De klasse SetterProcessor
wordt door de compiler gebruikt om de annotaties te verwerken. Het controleert of de methoden die zijn geannoteerd met de @Setter
annotatie public
, niet- static
methoden met een naam die begint met set
en een hoofdletter hebben als 4e letter. Als niet aan een van deze voorwaarden wordt voldaan, wordt er een fout geschreven naar de Messager
. De compiler schrijft dit naar stderr, maar andere tools kunnen deze informatie anders gebruiken. Met de NetBeans IDE kan de gebruiker bijvoorbeeld annotatieprocessors opgeven die worden gebruikt om foutmeldingen in de editor weer te geven.
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();
}
}
Packaging
Om door de compiler te worden toegepast, moet de annotatieprocessor beschikbaar worden gesteld aan de SPI (zie ServiceLoader ).
Hiertoe moet een tekstbestand META-INF/services/javax.annotation.processing.Processor
worden toegevoegd aan het jar-bestand met de annotatieprocessor en de annotatie naast de andere bestanden. Het bestand moet de volledig gekwalificeerde naam van de annotatieprocessor bevatten, dat wil zeggen dat het er zo uit moet zien
annotation.processor.SetterProcessor
We nemen aan dat het jar-bestand hieronder AnnotationProcessor.jar
wordt genoemd.
Voorbeeld geannoteerde klasse
De volgende klasse is een voorbeeldklasse in het standaardpakket waarbij de annotaties worden toegepast op de juiste elementen volgens het bewaarbeleid. Alleen de annotatieprocessor beschouwt de tweede methode echter alleen als een geldig annotatiedoel.
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) {}
}
De annotatieprocessor gebruiken met javac
Als de annotatieprocessor wordt ontdekt met behulp van de SPI, wordt deze automatisch gebruikt om geannoteerde elementen te verwerken. Bijvoorbeeld het compileren van de klasse AnnotationProcessorTest
met behulp van
javac -cp AnnotationProcessor.jar AnnotationProcessorTest.java
levert de volgende uitvoer op
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
in plaats van normaal te compileren. Er is geen .class
bestand gemaakt.
Dit kan worden voorkomen door de optie -proc:none
voor javac
. Je kunt ook afzien van de gebruikelijke compilatie door -proc:only
plaats daarvan op te geven.
IDE-integratie
Netbeans
Annotatieprocessors kunnen worden gebruikt in de NetBeans-editor. Hiervoor moet de annotatieprocessor worden opgegeven in de projectinstellingen:
ga naar
Project Properties
>Build
>Compiling
voeg vinkjes toe voor
Enable Annotation Processing
Enable Annotation Processing in Editor
klik op
Add
naast de lijst met annotatieprocessorsvoer in de pop-up die verschijnt de volledig gekwalificeerde klassenaam van de annotatieprocessor in en klik op
Ok
.
Resultaat
Het idee achter annotaties
De Java-taalspecificatie beschrijft annotaties als volgt:
Een annotatie is een markering die informatie koppelt aan een programmaconstructie, maar heeft geen effect tijdens runtime.
Annotaties kunnen vóór typen of verklaringen verschijnen. Het is mogelijk dat ze verschijnen op een plaats waar ze zowel op een type als op een verklaring van toepassing kunnen zijn.
Waar precies een annotatie op van toepassing is, wordt beheerst door de "meta-annotatie" @Target
. Zie "Aantekeningstypen definiëren" voor meer informatie.
Annotaties worden voor verschillende doeleinden gebruikt. Frameworks zoals Spring en Spring-MVC maken gebruik van annotaties om te bepalen waar afhankelijkheden moeten worden geïnjecteerd of waar verzoeken moeten worden gerouteerd.
Andere frameworks gebruiken annotaties voor het genereren van code. Lombok en JPA zijn uitstekende voorbeelden, die annotaties gebruiken om Java (en SQL) code te genereren.
Dit onderwerp biedt een uitgebreid overzicht van:
Hoe uw eigen annotaties definiëren?
Welke annotaties biedt de Java-taal?
Hoe worden annotaties in de praktijk gebruikt?
Annotaties voor 'dit' en ontvangerparameters
Toen Java-annotaties voor het eerst werden geïntroduceerd, was er geen voorziening voor het annoteren van het doel van een instantiemethode of de parameter verborgen constructor voor een constructor binnenklassen. Dit werd verholpen in Java 8 met toevoeging van declaraties van ontvangerparameters ; zie JLS 8.4.1 .
De ontvangerparameter is een optioneel syntactisch apparaat voor een instantiemethode of de constructor van een interne klasse. Voor een instantiemethode vertegenwoordigt de parameter ontvanger het object waarvoor de methode wordt aangeroepen. Voor de constructor van een binnenklasse vertegenwoordigt de parameter ontvanger de onmiddellijk omhullende instantie van het nieuw gebouwde object. Hoe dan ook, de ontvangerparameter bestaat uitsluitend om toe te staan dat het type van het gerepresenteerde object in broncode wordt aangegeven, zodat het type kan worden geannoteerd. De ontvangerparameter is geen formele parameter; preciezer gezegd, het is geen verklaring van enige vorm van variabele (§4.12.3), het is nooit gebonden aan enige waarde die als argument wordt doorgegeven in een methode aanroepexpressie of gekwalificeerde klasse-instantie creatie-expressie, en het heeft geen enkel effect op runtime.
Het volgende voorbeeld illustreert de syntaxis voor beide soorten ontvangerparameters:
public class Outer {
public class Inner {
public Inner (Outer this) {
// ...
}
public void doIt(Inner this) {
// ...
}
}
}
Het enige doel van ontvangerparameters is om u annotaties toe te voegen. U hebt bijvoorbeeld een aangepaste annotatie @IsOpen
die tot doel heeft te beweren dat een Closeable
object niet is gesloten wanneer een methode wordt aangeroepen. Bijvoorbeeld:
public class MyResource extends Closeable {
public void update(@IsOpen MyResource this, int value) {
// ...
}
public void close() {
// ...
}
}
Op één niveau kan de annotatie van @IsOpen
this
eenvoudig dienen als documentatie. We kunnen echter mogelijk meer doen. Bijvoorbeeld:
- Een annotatieprocessor kan een runtime-controle invoegen dat
this
zich niet in de gesloten status bevindt wanneerupdate
wordt aangeroepen. - Een codecontrole kan een statische code-analyse uitvoeren om gevallen te vinden waarin
this
kan worden afgesloten wanneer deupdate
wordt aangeroepen.
Voeg meerdere annotatiewaarden toe
Een annotatieparameter kan meerdere waarden accepteren als deze als een array is gedefinieerd. De standaard annotatie @SuppressWarnings
is bijvoorbeeld als volgt gedefinieerd:
public @interface SuppressWarnings {
String[] value();
}
De value
is een array van tekenreeksen. U kunt meerdere waarden instellen met behulp van een notatie die lijkt op Array-initializers:
@SuppressWarnings({"unused"})
@SuppressWarnings({"unused", "javadoc"})
Als u slechts één waarde hoeft in te stellen, kunnen de haakjes worden weggelaten:
@SuppressWarnings("unused")