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
@Retention(RetentionPolicy.RUNTIME) 
@interface MyAnnotation
CONSTRUCTOR constructeurs
@MyAnnotation
public MyClass() {}
VELD velden, enum-constanten
@XmlAttribute
private int count;
LOCAL_VARIABLE variabele verklaringen binnen methoden
for (@LoopVariable int i = 0; i < 100; i++) {
@Unused
String resultVariable;
}
PAKKET pakket (in package-info.java )
@Deprecated
package very.old;
METHODE methoden
@XmlElement
public int getCount() {...}
PARAMETER methode / constructorparameters
public Rectangle(
@NamedArg("width") double width,
@NamedArg("height") double height) {
...
}
TYPE klassen, interfaces, enums
@XmlRootElement
public class Report {}
Java SE 8
ElementType doelwit voorbeeld gebruik op doelelement
TYPE_PARAMETER Typ parameter verklaringen
public <@MyAnnotation T> void f(T t) {}
TYPE_USE Gebruik van een type
Object o = "42";
String s = (@MyAnnotation String) o;

@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 SE 8

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:

  1. ga naar Project Properties > Build > Compiling

  2. voeg vinkjes toe voor Enable Annotation Processing Enable Annotation Processing in Editor

  3. klik op Add naast de lijst met annotatieprocessors

  4. voer in de pop-up die verschijnt de volledig gekwalificeerde klassenaam van de annotatieprocessor in en klik op Ok .

Resultaat

Editor-venster met aangepast foutbericht

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 wanneer update wordt aangeroepen.
  • Een codecontrole kan een statische code-analyse uitvoeren om gevallen te vinden waarin this kan worden afgesloten wanneer de update 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") 


Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow