Java Language
Adnotacje
Szukaj…
Wprowadzenie
W Javie adnotacja jest formą metadanych syntaktycznych, które można dodać do kodu źródłowego Java. Dostarcza dane o programie, który nie jest częścią samego programu. Adnotacje nie mają bezpośredniego wpływu na działanie kodu, który adnotują. Klasy, metody, zmienne, parametry i pakiety mogą być opatrzone adnotacjami.
Składnia
- @AnnotationName // 'Adnotacja znacznika' (bez parametrów)
- @AnnotationName (someValue) // ustawia parametr o nazwie „wartość”
- @AnnotacjaNazwa (parametr1 = wartość1) // nazwany parametr
- @AnnotacjaNazwa (parametr1 = wartość1, parametr2 = wartość2) // wiele nazwanych parametrów
- @ AnnotationName (param1 = {1, 2, 3}) // nazwany parametr tablicy
- @AnnotacjaNazwa ({wartość1}) // tablica z pojedynczym elementem jako parametrem o nazwie „wartość”
Uwagi
Rodzaje parametrów
Dozwolone są tylko stałe wyrażenia następujących typów dla parametrów, a także tablice tych typów:
-
String
-
Class
- typy prymitywne
- Typy wyliczeń
- Typy adnotacji
Wbudowane adnotacje
Standardowa edycja Java zawiera wstępnie zdefiniowane adnotacje. Nie musisz ich definiować samodzielnie i możesz z nich korzystać natychmiast. Pozwalają one kompilatorowi na pewne podstawowe sprawdzanie metod, klas i kodu.
@Nadpisanie
Ta adnotacja dotyczy metody i mówi, że ta metoda musi zastąpić metodę „nadklasy” lub zaimplementować definicję metody abstrakcyjnej nadklasy. Jeśli ta adnotacja zostanie użyta z jakąkolwiek inną metodą, kompilator zgłosi błąd.
Betonowa nadklasa
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");
}
}
Klasa abstrakcyjna
abstract class Animal {
public abstract void makeNoise();
}
class Dog extends Animal {
// Fine
@Override
public void makeNoise() {
System.out.prinln("Woof");
}
}
Nie działa
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);
}
}
Głównym celem jest wyłapanie pomyłki, gdy myślisz, że przesłoniłeś metodę, ale w rzeczywistości definiujesz nową.
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");
}
}
Pamiętaj, że znaczenie @Override
zmieniało się z czasem:
- W Javie 5 oznaczało to, że metoda z adnotacjami musiała zastąpić nieabstrakcyjną metodę zadeklarowaną w łańcuchu nadklasy.
- Począwszy od języka Java 6, jest również spełnione, czy metoda z adnotacjami implementuje metodę abstrakcyjną zadeklarowaną w hierarchii nadklasy / interfejsu klas.
(Może to czasami powodować problemy podczas cofania kodu do Java 5.)
@Deprecated
Oznacza to, że metoda jest przestarzała. Może być tego kilka przyczyn:
interfejs API jest wadliwy i niepraktyczny do naprawienia,
korzystanie z interfejsu API może prowadzić do błędów,
interfejs API został zastąpiony przez inny interfejs API,
interfejs API jest przestarzały,
interfejs API jest eksperymentalny i podlega niezgodnym zmianom,
lub dowolna kombinacja powyższych.
Konkretny powód wycofania zwykle można znaleźć w dokumentacji interfejsu API.
Adnotacja spowoduje, że kompilator wyśle błąd, jeśli go użyjesz. IDE mogą również podkreślać tę metodę jako przestarzałą
class ComplexAlgorithm {
@Deprecated
public void oldSlowUnthreadSafeMethod() {
// stuff here
}
public void quickThreadSafeMethod() {
// client code should use this instead
}
}
@Tłumić ostrzeżenia
W prawie wszystkich przypadkach, gdy kompilator emituje ostrzeżenie, najodpowiedniejszym działaniem jest usunięcie przyczyny. W niektórych przypadkach (na przykład kod generyczny wykorzystujący kod pre-generyczny bezpieczny dla typu), może to nie być możliwe i lepiej jest ukryć te ostrzeżenia, których się spodziewasz i których nie można naprawić, aby lepiej widzieć nieoczekiwane ostrzeżenia.
Ta adnotacja może być zastosowana do całej klasy, metody lub linii. Jako parametr przyjmuje kategorię ostrzeżenia.
@SuppressWarnings("deprecation")
public class RiddledWithWarnings {
// several methods calling deprecated code here
}
@SuppressWarning("finally")
public boolean checkData() {
// method calling return from within finally block
}
Lepiej ograniczyć zakres adnotacji w jak największym stopniu, aby zapobiec również tłumieniu nieoczekiwanych ostrzeżeń. Na przykład ograniczenie zakresu adnotacji do pojedynczej linii:
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
Ostrzeżenia obsługiwane przez tę adnotację mogą się różnić w zależności od kompilatora. Tylko unchecked
i ostrzeżenia o deprecation
są wyraźnie wymienione w JLS. Nierozpoznane typy ostrzeżeń zostaną zignorowane.
@SafeVarargs
Z powodu kasowania typu void method(T... t)
zostanie przekonwertowana na void method(Object[] t)
co oznacza, że kompilator nie zawsze jest w stanie sprawdzić, czy użycie varargs jest bezpieczne dla danego typu. Na przykład:
private static <T> void generatesVarargsWarning(T... lists) {
Istnieją przypadki, w których użycie jest bezpieczne, w którym to przypadku można SafeVarargs
komentarz adnotacją SafeVarargs
aby wyłączyć ostrzeżenie. To oczywiście ukrywa ostrzeżenie, jeśli twoje użycie jest również niebezpieczne.
@Funkcjonalny interfejs
Jest to opcjonalna adnotacja używana do oznaczenia interfejsu FunctionalInterface. Spowoduje, że kompilator narzeka, jeśli nie jest zgodny ze specyfikacją FunctionalInterface (ma jedną abstrakcyjną metodę)
@FunctionalInterface
public interface ITrade {
public boolean check(Trade t);
}
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
Adnotacja w środowisku wykonawczym sprawdza się poprzez odbicie
Java Reflection API pozwala programiście przeprowadzać różne kontrole i operacje na polach klas, metodach i adnotacjach w czasie wykonywania. Jednak aby adnotacja była w ogóle widoczna w czasie wykonywania, RetentionPolicy
należy zmienić na RUNTIME
, jak pokazano w poniższym przykładzie:
@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));
}
}
Definiowanie typów adnotacji
Typy adnotacji są definiowane za pomocą @interface
. Parametry są zdefiniowane podobnie do metod zwykłego interfejsu.
@interface MyAnnotation {
String param1();
boolean param2();
int[] param3(); // array parameter
}
Wartości domyślne
@interface MyAnnotation {
String param1() default "someValue";
boolean param2() default true;
int[] param3() default {};
}
Meta-adnotacje
Meta-adnotacje to adnotacje, które można zastosować do typów adnotacji. Specjalne predefiniowane meta-adnotacje określają, w jaki sposób można używać typów adnotacji.
@Cel
Meta-adnotacja @Target
ogranicza typy, do których można zastosować adnotację.
@Target(ElementType.METHOD)
@interface MyAnnotation {
// this annotation can only be applied to methods
}
Za pomocą notacji tablicowej można dodać wiele wartości, np. @Target({ElementType.FIELD, ElementType.TYPE})
Dostępne wartości
ElementType | cel | przykładowe użycie elementu docelowego |
---|---|---|
ANNOTATION_TYPE | typy adnotacji | |
KONSTRUKTOR | konstruktory | |
POLE | pola, stałe wyliczeniowe | |
LOCAL_VARIABLE | deklaracje zmiennych wewnątrz metod | |
PAKIET | pakiet (w package-info.java ) | |
METODA | metody | |
PARAMETR | parametry metody / konstruktora | |
RODZAJ | klasy, interfejsy, wyliczenia | |
ElementType | cel | przykładowe użycie elementu docelowego |
---|---|---|
TYPE_PARAMETER | Wpisz deklaracje parametrów | |
TYPE_USE | Zastosowanie rodzaju | |
@Zatrzymywanie
Meta-adnotacja @Retention
określa widoczność adnotacji podczas procesu kompilacji lub wykonywania aplikacji. Domyślnie adnotacje są zawarte w plikach .class
, ale nie są widoczne w czasie wykonywania. Aby adnotacja była dostępna w środowisku wykonawczym, należy ustawić RetentionPolicy.RUNTIME
dla tej adnotacji.
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
// this annotation can be accessed with reflections at runtime
}
Dostępne wartości
Zasady przechowywania | Efekt |
---|---|
KLASA | Adnotacja jest dostępna w pliku .class , ale nie w czasie wykonywania |
RUNTIME | Adnotacja jest dostępna w czasie wykonywania i można uzyskać do niej dostęp poprzez odbicie |
ŹRÓDŁO | Adnotacja jest dostępna w czasie kompilacji, ale nie jest dodawana do plików .class . Adnotacja może być używana np. Przez procesor adnotacji. |
@Documented
Meta-adnotacja @Documented
służy do oznaczania adnotacji, których użycie powinno być udokumentowane przez generatory dokumentacji API, takie jak javadoc . Nie ma żadnych wartości. W przypadku @Documented
wszystkie klasy, które używają adnotacji, wyświetlą ją na swojej stronie dokumentacji. Bez @Documented
nie można zobaczyć, które klasy używają adnotacji w dokumentacji.
@Dziedziczny
@Inherited
meta-adnotacja ma zastosowanie do adnotacji, które są stosowane do klas. Nie ma żadnych wartości. Oznaczenie adnotacji jako @Inherited
zmienia sposób, w jaki działa zapytanie dotyczące adnotacji.
- W przypadku nie odziedziczonej adnotacji zapytanie sprawdza tylko badaną klasę.
- W przypadku odziedziczonej adnotacji kwerenda sprawdzi także łańcuch superklasy (rekurencyjnie), dopóki nie zostanie znaleziona instancja adnotacji.
Zauważ, że odpytywane są tylko superklasy: wszelkie adnotacje dołączone do interfejsów w hierarchii klas będą ignorowane.
@ Powtarzalne
Meta-adnotacja @Repeatable
została dodana w Javie 8. Wskazuje ona, że do instancji adnotacji można dołączyć wiele instancji adnotacji. Ta meta-adnotacja nie ma wartości.
Pobieranie wartości adnotacji w czasie wykonywania
Możesz pobrać bieżące właściwości adnotacji, używając Reflection, aby pobrać metodę lub pole lub klasę, do której zastosowano adnotację, a następnie pobrać pożądane właściwości.
@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);
}
}
}
Wyjście będzie
foo = bar
baz = buzz
Powtarzające się adnotacje
Do wersji Java 8 dwa wystąpienia tej samej adnotacji nie mogły być zastosowane do jednego elementu. Standardowym obejściem było użycie adnotacji kontenera zawierającej tablicę innych adnotacji:
// 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 zapewnia czystszy, bardziej przejrzysty sposób korzystania z adnotacji kontenera, z wykorzystaniem adnotacji @Repeatable
. Najpierw dodajemy to do klasy Author
:
@Repeatable(Authors.class)
Mówi to Javie, aby traktowało wiele adnotacji @Author
tak, jakby były otoczone kontenerem @Authors
. Możemy również użyć Class.getAnnotationsByType()
aby uzyskać dostęp do tablicy @Author
według jej własnej klasy, zamiast przez jej kontener:
@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
}
}
}
Odziedziczone adnotacje
Domyślnie adnotacje klasowe nie dotyczą typów rozszerzających je. Można to zmienić poprzez dodanie @Inherited
adnotacji definicji adnotacji
Przykład
Rozważ następujące 2 adnotacje:
@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface InheritedAnnotationType {
}
i
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface UninheritedAnnotationType {
}
Jeśli trzy klasy mają takie adnotacje:
@UninheritedAnnotationType
class A {
}
@InheritedAnnotationType
class B extends A {
}
class C extends B {
}
uruchamianie tego kodu
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));
wypisze wynik podobny do tego (w zależności od pakietów adnotacji):
null
@InheritedAnnotationType()
@InheritedAnnotationType()
_________________________________
@UninheritedAnnotationType()
null
null
Zauważ, że adnotacje można dziedziczyć tylko z klas, a nie z interfejsów.
Skompiluj przetwarzanie czasu za pomocą procesora adnotacji
Ten przykład pokazuje, jak wykonać sprawdzanie czasu kompilacji elementu z adnotacjami.
Adnotacja
Adnotacja @Setter
to marker, który można zastosować do metod. Adnotacja zostanie odrzucona podczas kompilacji, a później nie będzie dostępna.
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 {
}
Procesor adnotacji
Klasa SetterProcessor
jest używana przez kompilator do przetwarzania adnotacji. Sprawdza, czy metody opatrzone adnotacją @Setter
są public
, static
metodami o nazwie zaczynającej się od set
i posiadającej dużą literę jako 4 literę. Jeśli jeden z tych warunków nie zostanie spełniony, do Messager
zostanie zapisany błąd. Kompilator zapisuje to na stderr, ale inne narzędzia mogą wykorzystywać tę informację inaczej. Np. NetBeans IDE pozwala użytkownikowi określić procesory adnotacji, które są używane do wyświetlania komunikatów o błędach w edytorze.
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();
}
}
Opakowanie
Aby zastosować kompilator, procesor adnotacji musi zostać udostępniony SPI (patrz ServiceLoader ).
W tym celu plik jar META-INF/services/javax.annotation.processing.Processor
musi zostać dodany do pliku jar zawierającego procesor adnotacji i adnotację oprócz innych plików. Plik musi zawierać pełną nazwę procesora adnotacji, tzn. Powinien wyglądać tak
annotation.processor.SetterProcessor
Zakładamy, że plik jar nazywa się poniżej AnnotationProcessor.jar
.
Przykładowa klasa z adnotacjami
Następująca klasa to przykładowa klasa w pakiecie domyślnym z adnotacjami stosowanymi do poprawnych elementów zgodnie z zasadami przechowywania. Jednak tylko procesor adnotacji uważa drugą metodę za prawidłowy cel adnotacji.
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) {}
}
Korzystanie z procesora adnotacji z javac
Jeśli procesor adnotacji zostanie wykryty przy użyciu interfejsu SPI, jest automatycznie używany do przetwarzania elementów z adnotacjami. Np. Kompilacja klasy AnnotationProcessorTest
przy użyciu
javac -cp AnnotationProcessor.jar AnnotationProcessorTest.java
daje następujący wynik
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
zamiast kompilować normalnie. Nie utworzono pliku .class
.
Można temu zapobiec, określając opcję -proc:none
dla javac
. Możesz także zrezygnować ze zwykłej kompilacji, podając -proc:only
zamiast tego.
Integracja IDE
Netbeans
Procesory adnotacji mogą być używane w edytorze NetBeans. Aby to zrobić, procesor adnotacji musi zostać określony w ustawieniach projektu:
przejdź do
Project Properties
>Build
>Compiling
dodaj znaczniki
Enable Annotation Processing
iEnable Annotation Processing in Editor
kliknij
Add
obok listy procesorów adnotacjiw wyskakującym okienku wpisz pełną nazwę klasy procesora adnotacji i kliknij
Ok
.
Wynik
Idea Adnotacji
Specyfikacja języka Java opisuje adnotacje w następujący sposób:
Adnotacja jest znacznikiem, który wiąże informacje z konstrukcją programu, ale nie ma żadnego wpływu w czasie wykonywania.
Adnotacje mogą pojawiać się przed typami lub deklaracjami. Mogą pojawić się w miejscu, w którym mogą ubiegać się zarówno o typ, jak i deklarację.
To, czego dokładnie dotyczy adnotacja, jest regulowane przez „meta-adnotację” @Target
. Aby uzyskać więcej informacji, zobacz „Definiowanie typów adnotacji” .
Adnotacje są używane do wielu celów. Frameworki, takie jak Spring i Spring-MVC, wykorzystują adnotacje, aby określić, gdzie należy wstrzykiwać zależności lub gdzie należy kierować żądania.
Inne frameworki używają adnotacji do generowania kodu. Lombok i JPA to najlepsze przykłady, które wykorzystują adnotacje do generowania kodu Java (i SQL).
Ten temat ma na celu zapewnienie kompleksowego przeglądu:
Jak zdefiniować własne adnotacje?
Jakie adnotacje zapewnia język Java?
Jak adnotacje są używane w praktyce?
Adnotacje dla „tego” i parametrów odbiornika
Kiedy adnotacje Java zostały wprowadzone po raz pierwszy, nie było przepisu pozwalającego na adnotację celu metody instancji lub parametru ukrytego konstruktora dla konstruktora klas wewnętrznych. Zostało to naprawione w Javie 8 poprzez dodanie deklaracji parametrów odbiornika ; patrz JLS 8.4.1 .
Parametr odbiornika jest opcjonalnym urządzeniem syntaktycznym dla metody instancji lub konstruktora klasy wewnętrznej. W przypadku metody instancji parametr odbierający reprezentuje obiekt, dla którego metoda jest wywoływana. W przypadku konstruktora klasy wewnętrznej parametr odbierający reprezentuje bezpośrednio otaczającą instancję nowo zbudowanego obiektu. Tak czy inaczej, parametr odbiornika istnieje wyłącznie po to, aby umożliwić oznaczenie typu reprezentowanego obiektu w kodzie źródłowym, tak aby ten typ mógł zostać opatrzony adnotacjami. Parametr odbiornika nie jest parametrem formalnym; a dokładniej, nie jest to deklaracja jakiejkolwiek zmiennej (§4.12.3), nigdy nie jest związana z żadną wartością przekazywaną jako argument w wyrażeniu wywołania metody lub wyrażeniu tworzenia instancji klasy kwalifikowanej i nie ma żadnego wpływu na czas pracy.
Poniższy przykład ilustruje składnię dla obu rodzajów parametrów odbiornika:
public class Outer {
public class Inner {
public Inner (Outer this) {
// ...
}
public void doIt(Inner this) {
// ...
}
}
}
Jedynym celem parametrów odbiornika jest umożliwienie dodawania adnotacji. Na przykład możesz mieć niestandardową adnotację @IsOpen
której celem jest stwierdzenie, że obiekt Closeable
nie został zamknięty podczas wywołania metody. Na przykład:
public class MyResource extends Closeable {
public void update(@IsOpen MyResource this, int value) {
// ...
}
public void close() {
// ...
}
}
Na jednym poziomie adnotacja @IsOpen
na this
może po prostu służyć jako dokumentacja. Moglibyśmy jednak potencjalnie zrobić więcej. Na przykład:
- Procesor adnotacji mógł włożyć czek runtime, że
this
nie jest w stanie zamkniętym, gdyupdate
jest tzw. - Sprawdzania kod może wykonywać statycznej analizy kodu, aby znaleźć przypadki, gdzie
this
może być zamknięty, gdyupdate
jest tzw.
Dodaj wiele wartości adnotacji
Parametr adnotacji może przyjmować wiele wartości, jeśli jest zdefiniowany jako tablica. Na przykład standardowa adnotacja @SuppressWarnings
jest zdefiniowana w następujący sposób:
public @interface SuppressWarnings {
String[] value();
}
Parametr value
jest tablicą ciągów. Możesz ustawić wiele wartości, używając notacji podobnej do inicjatorów Array:
@SuppressWarnings({"unused"})
@SuppressWarnings({"unused", "javadoc"})
Jeśli musisz ustawić tylko jedną wartość, nawiasy można pominąć:
@SuppressWarnings("unused")