Java-аннотации используются для предоставления метаданных для вашего Java-кода. Будучи метаданными, напрямую не влияют на выполнение кода, хотя некоторые типы могут фактически использоваться для этой цели.
Цели
Обычно используются для следующих целей:
- компилятора;
- по сборке;
- по выполнению.
Java имеет 3 встроенных аннотации, которые вы можете использовать, чтобы давать инструкции компилятору.
Можно использовать во время сборки, когда вы создаете свой программный проект. Процесс включает в себя:
- генерацию исходного кода;
- компиляцию исходного кода;
- генерацию файлов XML (например, дескрипторов развертывания);
- упаковку скомпилированного кода и файлов в файл JAR и т. д.
Сборка программного обеспечения обычно выполняется с помощью инструмента автоматической сборки, такого как Apache Ant или Apache Maven. Инструменты могут сканировать ваш код на предмет конкретных аннотаций и генерировать исходный код или другие файлы на основе их.
Доступ через отражение Java
Обычно аннотации отсутствуют в вашем коде после компиляции. Однако можно определить свои собственные. Затем к ним получить доступ через Java Reflection и использовать, чтобы давать инструкции для вашей программы или какого-либо стороннего API.
Основы
@Entity
Символ @ сообщает компилятору, что это аннотация. Имя, следующее за символом @, является ее именем. В приведенном выше примере имя — Entity.
Элементы
@Entity(tableName = "vehicles")
Аннотация в этом примере содержит единственный элемент с именем tableName со значением, установленным для транспортных средств. Элементы заключены в круглые скобки после названия. Аннотации без элементов не нуждаются в скобках.
@Entity(tableName = "vehicles", primaryKey = "id")
@InsertNew(value = "yes")
@InsertNew("yes")
Размещение
@Entity
public class Vehicle {
}
Аннотация начинается с символа @, за которым следует имя. В этом случае имя — Entity.
@Entity
public class Vehicle {
@Persistent
protected String vehicleName = null;
@Getter
public String getVehicleName() {
return this.vehicleName;
}
public void setVehicleName(@Optional vehicleName) {
this.vehicleName = vehicleName;
}
public List addVehicleNameToList(List names) {
@Optional
List localNames = names;
if(localNames == null) {
localNames = new ArrayList();
}
localNames.add(getVehicleName());
return localNames;
}
}
Примечания не имеют конкретного значения в Java.
Встроенные
Java поставляется с тремя встроенными аннотациями, которые используются для предоставления инструкций компилятора Java:
- @Deprecated;
- @Override;
- @SuppressWarnings.
@Deprecated
@Deprecated
public class MyComponent {
}
Использование @Deprecated над объявлением класса помечает класс как устаревший.
Вы также можете использовать @Deprecated выше для описания методов и полей, чтобы пометить метод или поле как устаревшие.
@Deprecated
/**
@deprecated Use MyNewComponent instead.
*/
public class MyComponent {
}
@Override
@Override используется над методами, которые переопределяют методы в суперклассе. Если метод не соответствует методу в суперклассе, компилятор выдаст вам ошибку.
@Override не обязательна для переопределения метода в суперклассе. В случае, если кто-то изменил имя переопределенного метода в суперклассе, ваш метод подкласса больше не будет переопределять его. Без @Override вы бы не узнали об этом. С @Override компилятор скажет вам, что метод в подклассе не переопределяет ни один метод в суперклассе.
public class MySuperClass {
public void doTheThing() {
System.out.println("Do the thing");
}
}
public class MySubClass extends MySuperClass{
@Override
public void doTheThing() {
System.out.println("Do it differently");
}
}
В случае, если метод doTheThing() в MySuperClass изменяет подпись, так, что тот же метод в подклассе больше не переопределяет его, компилятор выдаст ошибку.
@SuppressWarnings
@SuppressWarnings заставляет компилятор подавлять предупреждения для данного метода. Например, если метод вызывает устаревший метод или выполняет небезопасное приведение типа, компилятор может сгенерировать предупреждение. Вы можете подавить эти предупреждения, пометив метод, содержащий код, @SuppressWarnings.
@SuppressWarnings
public void methodWithWarning() {
}
Создание собственных
Можно создавать свои собственные (пользовательские) аннотации. Определяются в своем собственном файле, как класс или интерфейс Java.
Пример
@interface MyAnnotation {
String value();
String name();
int age();
String[] newNames();
}
В этом примере определяется аннотация MyAnnotation, которая имеет четыре элемента. Обратите внимание на ключевое слово @interface. Это сигнализирует компилятору Java, что это определение примечаний.
Обратите внимание, что каждый элемент определяется аналогично определению метода в интерфейсе. У него есть тип данных и имя. Вы можете использовать все примитивные типы данных, а также массивы в качестве типа данных элемента. Сложные объекты в качестве типа данных не применяются.
@MyAnnotation(
value="123",
name="Jakob",
age=37,
newNames={"Jenkov", "Peterson"}
)
public class MyClass {
}
Как видите, я должен указать значения для всех элементов аннотации MyAnnotation.
Значения элемента по умолчанию
@interface MyAnnotation {
String value() default "";
String name();
int age();
String[] newNames();
}
@MyAnnotation(
name="Jakob",
age=37,
newNames={"Jenkov", "Peterson"}
)
public class MyClass {
}
Обратите внимание, что элемент значения больше не присутствует.
@Retention
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
Это то, что сигнализирует компилятору Java и JVM, что аннотация должна быть доступна через отражение во время выполнения.
Класс RetentionPolicy содержит еще два значения, которые вы можете использовать:
- RetentionPolicy.CLASS означает, что примечание хранится в файле .class, но недоступна во время выполнения. Это политика хранения по умолчанию, если вы вообще не указали политику хранения.
- RetentionPolicy.SOURCE означает, что примечание доступно только в исходном коде, а не в файлах .class и не во время выполнения. Если создаете свои собственные аннотации для использования с инструментами сборки, которые сканируют код, можете использовать эту политику хранения. Таким образом, файлы .class не загрязняются без необходимости.
@Target
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target({ElementType.METHOD})
public @interface MyAnnotation {
String value();
}
В этом примере показана аннотация, которую можно использовать только для аннотирования методов.
Класс ElementType содержит следующие возможные цели:
- ElementType.ANNOTATION_TYPE;
- ElementType.CONSTRUCTOR;
- ElementType.FIELD;
- ElementType.LOCAL_VARIABLE;
- ElementType.METHOD;
- ElementType.PACKAGE;
- ElementType.PARAMETER;
- ElementType.TYPE.
Большинство из них самоочевидны, но некоторые нет. Поэтому я объясню цели, которые не очевидны.
Цель ANNOTATION_TYPE означает определение. Таким образом, аннотация может использоваться только для аннотирования других примечаний. Как @Target и @Retention.
Цель TYPE означает любой тип. Тип — это класс, интерфейс, перечисление или аннотация.
@Inherited
java.lang.annotation.Inherited
@Inherited
public @interface MyAnnotation {
}
@MyAnnotation
public class MySuperClass { ... }
public class MySubClass extends MySuperClass { ... }
В этом примере класс MySubClass наследует аннотацию @MyAnnotation, потому что MySubClass наследуется от MySuperClass, а MySuperClass имеет @MyAnnotation.
@Documented
import java.lang.annotation.Documented;
@Documented
public @interface MyAnnotation {
}
@MyAnnotation
public class MySuperClass { ... }
При генерации JavaDoc для класса MySuperClass @MyAnnotation теперь включается в JavaDoc.
