Java Language
Anmerkungen
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 | |
KONSTRUKTEUR | Konstruktoren | |
FELD | Felder, Enumenkonstanten | |
LOKALE VARIABLE | Variablendeklarationen innerhalb von Methoden | |
PAKET | Paket (in package-info.java ) | |
METHODE | Methoden | |
PARAMETER | Methoden- / Konstruktorparameter | |
ART | Klassen, Schnittstellen, Enums | |
ElementType | Ziel | Beispiel für die Verwendung auf dem Zielelement |
---|---|---|
TYPE_PARAMETER | Geben Sie Parameterdeklarationen ein | |
TYPE_USE | Verwendung eines Typs | |
@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 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:
Gehen Sie zu
Project Properties
>Build
>Compiling
Hinzufügen von Häkchen für
Enable Annotation Processing
undEnable Annotation Processing in Editor
Klicken
Add
neben der Anmerkungsprozessorliste aufAdd
Geben Sie im angezeigten Popup den vollständig qualifizierten Klassennamen des Anmerkungsprozessors ein und klicken Sie auf
Ok
.
Ergebnis
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 dasupdate
aufgerufen wird. - Ein Code-Checker könnte eine statische Code-Analyse durchführen, um Fälle zu finden, in denen
this
beim Aufruf derupdate
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")