Suche…


Einführung

In Java ist eine Annotation eine Form von syntaktischen Metadaten, die dem Java-Quellcode hinzugefügt werden können. Sie liefert Daten zu einem Programm, das nicht Teil des Programms selbst ist. Anmerkungen haben keinen direkten Einfluss auf die Funktionsweise des Codes, den sie kommentieren. Klassen, Methoden, Variablen, Parameter und Pakete dürfen kommentiert werden.

Syntax

  • @AnnotationsName // 'Markierungsanmerkung' (keine Parameter)
  • @AnnotationName (someValue) // setzt Parameter mit dem Namen 'value'
  • @Anmerkungsname (Parameter1 = Wert1) // benannter Parameter
  • @Annotationsname (Parameter1 = Wert1, Parameter2 = Wert2) // mehrere benannte Parameter
  • @Anmerkungsname (param1 = {1, 2, 3}) // benannter Array-Parameter
  • @AnnotationsName ({value1}) // Array mit einem einzelnen Element als Parameter mit dem Namen 'value'

Bemerkungen

Parametertypen

Für Parameter sowie Arrays dieser Typen sind nur konstante Ausdrücke der folgenden Typen zulässig:

  • String
  • Class
  • primitive Typen
  • Aufzählungstypen
  • Anmerkungsarten

Eingebaute Anmerkungen

Die Standard Edition von Java enthält einige vordefinierte Anmerkungen. Sie müssen sie nicht selbst definieren und können sie sofort verwenden. Sie ermöglichen dem Compiler, einige grundlegende Überprüfungen von Methoden, Klassen und Code zu ermöglichen.

@Überfahren

Diese Anmerkung gilt für eine Methode und besagt, dass diese Methode die Methode einer Superklasse überschreiben oder die Methodendefinition einer abstrakten Superklasse implementieren muss. Wenn diese Annotation mit einer anderen Methode verwendet wird, gibt der Compiler einen Fehler aus.

Konkrete Oberklasse

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

Abstrakte Klasse

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

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

Funktioniert nicht

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

Der Hauptzweck besteht darin, die falsche Schreibweise abzufangen, wenn Sie der Meinung sind, dass Sie eine Methode überschreiben, aber tatsächlich eine neue definieren.

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

Beachten Sie, dass sich die Bedeutung von @Override im Laufe der Zeit geändert hat:

  • In Java 5 bedeutete dies, dass die annotierte Methode eine nicht abstrakte Methode überschreiben musste, die in der Superklassenkette deklariert wurde.
  • Ab Java 6 ist es auch erfüllt, wenn die annotierte Methode eine abstrakte Methode implementiert, die in der Klassen-Superklasse / Schnittstellen-Hierarchie deklariert ist.

(Dies kann gelegentlich zu Problemen führen, wenn Code nach Java 5 zurück portiert wird.)

@Entschieden

Dies kennzeichnet die Methode als veraltet. Dafür kann es mehrere Gründe geben:

  • Die API ist fehlerhaft und unpraktisch zu beheben.

  • Die Verwendung der API führt wahrscheinlich zu Fehlern.

  • Die API wurde durch eine andere API ersetzt.

  • die API ist veraltet,

  • Die API ist experimentell und unterliegt inkompatiblen Änderungen.

  • oder eine Kombination der oben genannten.

Der spezifische Grund für die Abwertung ist in der Regel in der Dokumentation der API zu finden.


Die Anmerkung führt dazu, dass der Compiler einen Fehler ausgibt, wenn Sie ihn verwenden. IDEs können diese Methode auch als veraltet markieren

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

@SuppressWarnings

In fast allen Fällen ist es am besten, wenn der Compiler eine Warnung ausgibt, die Ursache zu beheben. In einigen Fällen (z. B. Generics-Code, der untypensicheren Prägenerics-Code verwendet) ist dies möglicherweise nicht möglich, und es ist besser, diese Warnungen zu unterdrücken, die Sie erwarten und nicht beheben können, sodass Sie unerwartete Warnungen deutlicher sehen können.

Diese Annotation kann auf eine ganze Klasse, Methode oder Zeile angewendet werden. Die Kategorie der Warnung wird als Parameter verwendet.

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

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

Es ist besser, den Umfang der Anmerkung so weit wie möglich einzuschränken, um zu verhindern, dass unerwartete Warnungen ebenfalls unterdrückt werden. B. den Umfang der Annotation auf eine einzelne Zeile beschränken:

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

Die von dieser Anmerkung unterstützten Warnungen können von Compiler zu Compiler variieren. In der JLS werden nur die unchecked und deprecation Warnungen ausdrücklich erwähnt. Nicht erkannte Warntypen werden ignoriert.

@SafeVarargs

Aufgrund der Typlöschung wird die void method(T... t) in die void method(Object[] t) konvertiert. Dies bedeutet, dass der Compiler nicht immer überprüfen kann, ob die Verwendung von varargs typsicher ist. Zum Beispiel:

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

Es gibt Fälle, in denen die Verwendung sicher ist. In diesem Fall können Sie die Methode mit der SafeVarargs Anmerkung versehen, um die Warnung zu unterdrücken. Dies verbirgt offensichtlich die Warnung, wenn Ihre Verwendung ebenfalls unsicher ist.

@Funktionsschnittstelle

Dies ist eine optionale Anmerkung zum Markieren eines FunctionalInterface. Der Compiler wird beschwert, wenn er nicht mit der FunctionalInterface-Spezifikation übereinstimmt (eine einzige abstrakte Methode hat).

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

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

Laufzeitannotationsprüfungen über Reflection

Mit der Reflection-API von Java kann der Programmierer während der Laufzeit verschiedene Prüfungen und Vorgänge an Klassenfeldern, Methoden und Anmerkungen durchführen. Damit eine Anmerkung zur Laufzeit überhaupt sichtbar ist, muss die RetentionPolicy in RUNTIME geändert RUNTIME , wie im folgenden Beispiel gezeigt:

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

Anmerkungsarten definieren

Annotationstypen werden mit @interface definiert. Parameter werden ähnlich den Methoden einer regulären Schnittstelle definiert.

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

Standardwerte

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

Meta-Anmerkungen

Meta-Annotationen sind Annotationen, die auf Annotationstypen angewendet werden können. Spezielle vordefinierte Meta-Annotationen definieren, wie Annotationstypen verwendet werden können.

@Ziel

Die @Target - @Target beschränkt die Typen, auf die die Annotation angewendet werden kann.

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

Mehrere Werte können mithilfe der Array-Notation hinzugefügt werden, z. B. @Target({ElementType.FIELD, ElementType.TYPE})

Verfügbare Werte

ElementType Ziel Beispiel für die Verwendung auf dem Zielelement
ANNOTATION_TYPE Anmerkungsarten
@Retention(RetentionPolicy.RUNTIME) 
@interface MyAnnotation
KONSTRUKTEUR Konstruktoren
@MyAnnotation
public MyClass() {}
FELD Felder, Enumenkonstanten
@XmlAttribute
private int count;
LOKALE VARIABLE Variablendeklarationen innerhalb von Methoden
for (@LoopVariable int i = 0; i < 100; i++) {
@Unused
String resultVariable;
}
PAKET Paket (in package-info.java )
@Deprecated
package very.old;
METHODE Methoden
@XmlElement
public int getCount() {...}
PARAMETER Methoden- / Konstruktorparameter
public Rectangle(
@NamedArg("width") double width,
@NamedArg("height") double height) {
...
}
ART Klassen, Schnittstellen, Enums
@XmlRootElement
public class Report {}
Java SE 8
ElementType Ziel Beispiel für die Verwendung auf dem Zielelement
TYPE_PARAMETER Geben Sie Parameterdeklarationen ein
public <@MyAnnotation T> void f(T t) {}
TYPE_USE Verwendung eines Typs
Object o = "42";
String s = (@MyAnnotation String) o;

@Retention

Die Meta-Annotation @Retention definiert die Annotationssichtbarkeit während des Kompilierungsprozesses oder der Ausführung von Anwendungen. Standardmäßig sind Annotationen in .class Dateien enthalten, zur Laufzeit jedoch nicht sichtbar. Um eine Annotation zur Laufzeit zugänglich zu machen, muss RetentionPolicy.RUNTIME für diese Annotation festgelegt werden.

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

Verfügbare Werte

Aufbewahrungsrichtlinie Bewirken
KLASSE Die Anmerkung ist in der .class Datei verfügbar, jedoch nicht zur Laufzeit
LAUFZEIT Die Anmerkung ist zur Laufzeit verfügbar und kann über Reflection aufgerufen werden
QUELLE Die Anmerkung ist zur Kompilierzeit verfügbar, wird jedoch nicht zu den .class Dateien hinzugefügt. Die Annotation kann zB von einem Annotationsprozessor verwendet werden.

@Dokumentiert

Mit der @Documented Meta-Annotation werden Annotationen markiert, deren Verwendung von API-Dokumentationsgeneratoren wie Javadoc dokumentiert werden soll. Es hat keine Werte. Bei @Documented werden alle Klassen, die die Annotation verwenden, auf ihrer generierten Dokumentationsseite @Documented . Ohne @Documented ist nicht @Documented , welche Klassen die Annotation in der Dokumentation verwenden.

@Vererbt

Die @Inherited ist für Annotationen relevant, die auf Klassen angewendet werden. Es hat keine Werte. Durch das Markieren einer Annotation als @Inherited die Funktionsweise der Annotationsabfrage @Inherited .

  • Bei einer nicht geerbten Annotation untersucht die Abfrage nur die Klasse, die untersucht wird.
  • Bei einer geerbten Annotation überprüft die Abfrage auch die übergeordnete Kette (rekursiv), bis eine Instanz der Annotation gefunden wird.

Beachten Sie, dass nur die Superklassen abgefragt werden: Anmerkungen, die an Schnittstellen in der Klassenhierarchie angefügt sind, werden ignoriert.

@Wiederholbar

Die @Repeatable Meta-Annotation wurde in Java 8 hinzugefügt. Sie zeigt an, dass mehrere Instanzen der Annotation dem Ziel der Annotation zugeordnet werden können. Diese Meta-Annotation hat keine Werte.

Annotationswerte zur Laufzeit abrufen

Sie können die aktuellen Eigenschaften der Annotation abrufen, indem Sie Reflection verwenden , um die Methode oder das Feld oder die Klasse mit einer Annotation abzurufen, und anschließend die gewünschten Eigenschaften abzurufen.

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

Die Ausgabe wird sein

foo = bar
baz = buzz

Anmerkungen wiederholen

Bis Java 8 konnten zwei Instanzen derselben Anmerkung nicht auf ein einzelnes Element angewendet werden. Die standardmäßige Problemumgehung bestand in der Verwendung einer Container-Annotation, die ein Array mit einer anderen Annotation enthält:

// 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 bietet eine sauberere und transparentere Methode zur Verwendung von Containerkommentaren mithilfe der Annotation @Repeatable . Zuerst fügen wir dies der Author Klasse hinzu:

@Repeatable(Authors.class)

Dies weist Java an, mehrere @Author Anmerkungen so zu behandeln, als wären sie vom @Authors Container umgeben. Wir können Class.getAnnotationsByType() auch verwenden, um auf das @Author Array von seiner eigenen Klasse zuzugreifen, anstatt über seinen 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
        }
    }
}

Vererbte Anmerkungen

Standardmäßig gelten Klassenanmerkungen nicht für Typen, die sie erweitern. Dies kann durch Hinzufügen der Annotation @Inherited zur Annotationsdefinition geändert werden

Beispiel

Beachten Sie die folgenden 2 Anmerkungen:

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

und

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

Wenn drei Klassen so kommentiert werden:

@UninheritedAnnotationType
class A {
}

@InheritedAnnotationType
class B extends A {
}

class C extends B {
}

diesen Code ausführen

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

gibt ein ähnliches Ergebnis aus (abhängig von den Paketen der Anmerkung):

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

Beachten Sie, dass Anmerkungen nur von Klassen und nicht von Schnittstellen geerbt werden können.

Compilierzeitverarbeitung mit Anmerkungsprozessor

In diesem Beispiel wird veranschaulicht, wie die Kompilierzeit eines kommentierten Elements überprüft wird.

Die Anmerkung

Die @Setter Annotation ist eine Markierung, die auf Methoden angewendet werden kann. Die Annotation wird während des Kompilierens nicht mehr verfügbar sein.

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

Der Anmerkungsprozessor

Die SetterProcessor Klasse wird vom Compiler zur Verarbeitung der Anmerkungen verwendet. Es prüft, ob die mit der @Setter Annotation annotierten Methoden public , nicht static Methoden mit einem Namen, der mit set beginnt und einen Großbuchstaben als vierten Buchstaben hat. Wenn eine dieser Bedingungen nicht erfüllt ist, wird ein Fehler in den Messager . Der Compiler schreibt dies in stderr, aber andere Tools könnten diese Informationen anders verwenden. In der NetBeans-IDE kann der Benutzer beispielsweise Anmerkungsprozessoren angeben, die zum Anzeigen von Fehlernachrichten im Editor verwendet werden.

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

}

Verpackung

Um vom Compiler angewendet zu werden, muss der Anmerkungsprozessor der SPI zur Verfügung gestellt werden (siehe ServiceLoader ).

Dazu muss eine Textdatei META-INF/services/javax.annotation.processing.Processor zur JAR-Datei hinzugefügt werden, die den Anmerkungsprozessor und die Anmerkung zusätzlich zu den anderen Dateien enthält. Die Datei muss den vollständig qualifizierten Namen des Anmerkungsprozessors enthalten, dh es sollte so aussehen

annotation.processor.SetterProcessor

Wir nehmen an, dass die JAR-Datei unten als AnnotationProcessor.jar wird.

Beispiel kommentierte Klasse

Die folgende Klasse ist eine Beispielklasse im Standardpaket, wobei die Anmerkungen gemäß der Aufbewahrungsrichtlinie auf die richtigen Elemente angewendet werden. Nur der Anmerkungsprozessor betrachtet jedoch nur die zweite Methode als gültiges Anmerkungsziel.

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

Verwenden des Anmerkungsprozessors mit Javac

Wenn der Anmerkungsprozessor mithilfe der SPI erkannt wird, wird er automatisch zur Verarbeitung von Anmerkungselementen verwendet. ZB Kompilieren der AnnotationProcessorTest Klasse mit

javac -cp AnnotationProcessor.jar AnnotationProcessorTest.java

ergibt die folgende Ausgabe

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

anstatt normal zu kompilieren. Es wird keine .class Datei erstellt.

Dies könnte durch die Angabe der verhindert werden -proc:none Option für javac . Sie können auch auf die übliche Kompilierung verzichten, indem -proc:only stattdessen -proc:only .

IDE-Integration

Netbeans

Anmerkungsprozessoren können im NetBeans-Editor verwendet werden. Dazu muss der Anmerkungsprozessor in den Projekteinstellungen angegeben werden:

  1. Gehen Sie zu Project Properties > Build > Compiling

  2. Hinzufügen von Häkchen für Enable Annotation Processing und Enable Annotation Processing in Editor

  3. Klicken Add neben der Anmerkungsprozessorliste auf Add

  4. Geben Sie im angezeigten Popup den vollständig qualifizierten Klassennamen des Anmerkungsprozessors ein und klicken Sie auf Ok .

Ergebnis

Editorfenster mit benutzerdefinierter Fehlermeldung

Die Idee hinter den Anmerkungen

In der Java-Sprachspezifikation werden Annotationen wie folgt beschrieben:

Eine Annotation ist eine Markierung, die Informationen mit einem Programmkonstrukt verknüpft, jedoch zur Laufzeit keine Auswirkungen hat.

Anmerkungen können vor Typen oder Deklarationen erscheinen. Es ist möglich, dass sie an einem Ort erscheinen, an dem sie sich sowohl auf einen Typ als auch auf eine Deklaration beziehen können.
Für was genau eine Anmerkung gilt, wird von @Target "meta-annotation" @Target . Weitere Informationen finden Sie unter "Annotationstypen definieren" .

Anmerkungen werden für eine Vielzahl von Zwecken verwendet. Frameworks wie Spring und Spring-MVC verwenden Anmerkungen, um zu definieren, wo Abhängigkeiten eingefügt werden sollen oder wohin Anforderungen geleitet werden sollen.

Andere Frameworks verwenden Annotationen für die Codegenerierung. Lombok und JPA sind erstklassige Beispiele, die Annotationen verwenden, um Java-Code (und SQL-Code) zu erstellen.

Dieses Thema soll einen umfassenden Überblick über Folgendes vermitteln:

  • Wie definiere ich eigene Anmerkungen?

  • Welche Anmerkungen bietet die Java-Sprache?

  • Wie werden Annotationen in der Praxis verwendet?

Anmerkungen für 'this' und Empfängerparameter

Bei der Einführung von Java-Annotationen war es nicht vorgesehen, das Ziel einer Instanzmethode oder den Parameter für einen ausgeblendeten Konstruktor für einen Konstruktor für innere Klassen zu kommentieren. Dies wurde in Java 8 durch Hinzufügen von Empfängerparameterdeklarationen behoben. siehe JLS 8.4.1 .

Der Empfängerparameter ist ein optionales syntaktisches Gerät für eine Instanzmethode oder den Konstruktor einer inneren Klasse. Bei einer Instanzmethode stellt der Empfängerparameter das Objekt dar, für das die Methode aufgerufen wird. Für den Konstruktor einer inneren Klasse stellt der Empfängerparameter die unmittelbar einschließende Instanz des neu erstellten Objekts dar. In beiden Fällen ist der Empfängerparameter nur vorhanden, um zu ermöglichen, dass der Typ des dargestellten Objekts im Quellcode angegeben wird, sodass der Typ mit Anmerkungen versehen werden kann. Der Empfängerparameter ist kein formaler Parameter. Genauer gesagt, es handelt sich nicht um eine Deklaration irgendeiner Art von Variable (§4.12.3), sie ist niemals an einen Wert gebunden, der als Argument in einem Methodenaufrufausdruck oder einem qualifizierten Klasseninstanzerstellungsausdruck übergeben wird Laufzeit

Das folgende Beispiel veranschaulicht die Syntax für beide Arten von Empfängerparametern:

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

Der einzige Zweck der Empfängerparameter besteht darin, dass Sie Anmerkungen hinzufügen können. Beispielsweise haben Sie möglicherweise eine benutzerdefinierte Annotation @IsOpen deren Zweck darin besteht, zu bestätigen, dass ein Closeable Objekt beim Closeable einer Methode nicht geschlossen wurde. Zum Beispiel:

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

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

Auf einer Ebene könnte die @IsOpen Anmerkung this einfach als Dokumentation dienen. Wir könnten jedoch möglicherweise mehr tun. Zum Beispiel:

  • Ein Anmerkungsprozessor könnte eine Laufzeitüberprüfung einfügen, die besagt, dass sich this nicht im geschlossenen Zustand befindet, wenn das update aufgerufen wird.
  • Ein Code-Checker könnte eine statische Code-Analyse durchführen, um Fälle zu finden, in denen this beim Aufruf der update geschlossen werden könnte .

Fügen Sie mehrere Anmerkungswerte hinzu

Ein Annotation-Parameter kann mehrere Werte akzeptieren, wenn er als Array definiert ist. Zum Beispiel ist die Standardannotation @SuppressWarnings folgendermaßen definiert:

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

Der value Parameter ist ein Array von Strings. Sie können mehrere Werte festlegen, indem Sie eine Notation verwenden, die den Array-Initialisierern ähnelt:

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

Wenn Sie nur einen einzelnen Wert festlegen müssen, können die Klammern weggelassen werden:

@SuppressWarnings("unused") 


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow