Итак, что же такое аннотации в Java?
Согласно спецификации, аннотация — это маркер, который связывает определенную информацию с программной конструкцией, но не оказывает прямого влияния на выполнение аннотируемого кода.
Какие программные конструкции могут быть аннотированы?
На самом деле, аннотацией может быть помечено практически всё, что угодно: пакет, класс (интерфейс, перечисление), конструктор, метод, поле класса, аргумент метода, локальная переменная в методе, объявление типа у типизированного класса, метода или конструктора, в выражениях
Причем объявление аннотации может быть помечено самой этой аннотацией — и это будет работать, циркулярность в отношении аннотаций допускается. То есть это вполне валидный код:
Аннотации, которыми помечают объявления аннотаций, называются мета-аннотациями.
Кстати, собака (
Класс аннотации представляет собой специальный вид интерфейса. Несмотря на то, что это явно не указывается, все аннотации являются наследниками интерфейса
Возвращаемым значением этих методов могут быть:
Также в классе аннотации можно указать для методов значения по умолчанию, с помощью ключевого слова
Соответственно, для тех методов, у которых имеется значение по умолчанию, при использовании аннотации передавать значение не обязательно.
Небольшой пример:
Есть 2 сокращённых формы использования аннотаций — одноэлементная и маркерная.
Если у аннотации один метод называется
Если же у аннотации нет методов или у всех методов есть значения по умолчанию — её можно использовать , как маркерную. То есть, если нас устраивают значения по умолчанию и мы не хотим передавать другие, то можно не ставить пустые скобки, а вообще опустить их.
5 встроенных мета-аннотаций Java:
1)
4)
5)
Пожалуй, это вся основная информация по аннотациям в Java.
Материал написан на основе спецификации Java 8 (HTML | PDF).
Согласно спецификации, аннотация — это маркер, который связывает определенную информацию с программной конструкцией, но не оказывает прямого влияния на выполнение аннотируемого кода.
Какие программные конструкции могут быть аннотированы?
На самом деле, аннотацией может быть помечено практически всё, что угодно: пакет, класс (интерфейс, перечисление), конструктор, метод, поле класса, аргумент метода, локальная переменная в методе, объявление типа у типизированного класса, метода или конструктора, в выражениях
extends
, implements
, instanceof
, блоках try-with-resources, объявление типа исключения в выражениях catch
, throws
и даже сами классы аннотаций.Причем объявление аннотации может быть помечено самой этой аннотацией — и это будет работать, циркулярность в отношении аннотаций допускается. То есть это вполне валидный код:
Java:
package ru.worldjb;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
@WorldjbAnnotation
@Target(ElementType.TYPE)
public @interface WorldjbAnnotation {
}
Аннотации, которыми помечают объявления аннотаций, называются мета-аннотациями.
Кстати, собака (
@
) — это самостоятельный ключевой символ, его можно отделить, например, пробелом — будет работать, но так делать не рекомендуется, так как это нарушает code style, также как и отделение пробелом многоточия в varargs.Класс аннотации представляет собой специальный вид интерфейса. Несмотря на то, что это явно не указывается, все аннотации являются наследниками интерфейса
java.lang.annotation.Annotation
и наследовать другие интерфейсы не могут. Поскольку это интерфейсы, то они могут иметь только абстрактные методы. Причем без аргументов.Возвращаемым значением этих методов могут быть:
- примитивы
String
Class
- перечисление (
enum
) - аннотация
- плоский (одномерный) массив элементов любого из вышеперечисленных типов
Также в классе аннотации можно указать для методов значения по умолчанию, с помощью ключевого слова
default
после имени метода и скобок.Соответственно, для тех методов, у которых имеется значение по умолчанию, при использовании аннотации передавать значение не обязательно.
Небольшой пример:
Java:
package ru.worldjb;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface WorldjbAnnotation {
int id();
String[] strings() default "WorldJB"; // Значение по умолчанию.
// В массив оборачивать не обязательно, компилятор сделает это за нас.
}
Java:
package ru.worldjb;
@WorldjbAnnotation(id = 1) // id передали, а strings — не обязательно
public class WorldJB {
public static void main(String[] args) {
System.out.println("Hello, WorldJB!");
}
}
Есть 2 сокращённых формы использования аннотаций — одноэлементная и маркерная.
Если у аннотации один метод называется
value
, а все остальные (если они есть) имеют значения по умолчанию, то её можно использовать как одноэлементную. То есть, если мы хотим передать только значение для метода value
, а для остальных (если они есть) нас устраивают значения по умолчанию, мы можем в скобках вместо value = значение просто указать значение.Если же у аннотации нет методов или у всех методов есть значения по умолчанию — её можно использовать , как маркерную. То есть, если нас устраивают значения по умолчанию и мы не хотим передавать другие, то можно не ставить пустые скобки, а вообще опустить их.
5 встроенных мета-аннотаций Java:
1)
@Retention
- политика сохранения аннотации. Может принимать одно из 3 значений:RetentionPolicy.SOURCE
— аннотация сохраняется только в исходном коде и отбрасывается компилятором. То есть в байт-коде её не будет. Такие аннотации, как правило, обрабатываются AnnotationProcessor-ами — специальными классами, которые имплементируют интерфейсjavax.annotation.processing.Processor
и прописываются в файле META-INF/services/javax.annotation.processing.Processor внутри JAR. Компилятор проверяет все JAR-ы в classpath на наличие этого файла и вызывает все AnnotationProcessor-ы. Обычно это используется для автогенерации кода.RetentionPolicy.CLASS
— политика сохранения аннотаций по умолчанию — аннотация будет в байт-коде, но в рантайме через reflection она доступна не будет. Обычно используется для всяких AST трансформаций и прочих манипуляций с байт-кодом.RetentionPolicy.RUNTIME
— аннотация будет доступна в рантайме. Позволяет обрабатывать аннотации в рантайме. Используется в основном для dependency injection и подобных вещей.
@Target
- массив типов элементов, которые могут быть аннотированы данной аннотацией (по умолчанию аннотацией может быть помечено всё, кроме объявления типа параметра в параметризованных классах, методах и конструкторах):ElementType.PACKAGE
- объявление пакетаElementType.TYPE
- объявление класса, интерфейса, перечисления или типа аннотацииElementType.ANNOTATION_TYPE
- объявление типа аннотации (полезно для мета-аннотаций)ElementType.METHOD
- объявление метода, включая методы аннотацийElementType.CONSTRUCTOR
- объявление конструктораElementType.TYPE_PARAMETER
- объявление параметров типов параметризованных классов, интерфейсов, методов и конструкторовElementType.FIELD
- объявление поля классаElementType.PARAMETER
- объявление формального параметра (параметра метода, конструктора) или параметра исключения (в блоке catch)ElementType.LOCAL_VARIABLE
- объявление локальной переменной в методе или конструкторе, в том числе в циклеfor
и блоке try-with-resourcesElementType.TYPE_USE
- тип в выраженияхextends
иimplements
в объявлении класса; тип в выраженииextends
в объявлении интерфейса; тип возвращаемого значения метода (включая методы аннотаций); тип в выраженииthrows
в объявлении метода или конструктора; тип в выраженииextends
в объявлении параметра типа типизированного класса, интерфейса, метода или конструктора; тип поля класса или интерфейса (включаяenum
константы); тип формального параметра метода, конструктора или лямбда-выражения; тип параметра получателя метода (для вложенных классов); тип локальной переменной; тип исключения (вcatch
,throws
); тип в списке аргументов для вызова конструктора или выражения создания экземпляра класса или вызова метода; в выражении создания экземпляра класса, в качестве экземпляра класса, для которого создается экземпляр, или в качестве прямого суперкласса или прямого суперинтерфейса анонимного класса, для которого создается экземпляр; тип элемента в выражении создания массива; тип в операторе приведения типа; тип, который следует за операторомinstanceof
; в выражении ссылки на метод в качестве ссылочного типа для поиска метода-члена или в качестве типа класса или типа массива для построения.
@Repeatable
- позволяет сделать аннотацию повторяемой, т.е. получить возможность несколько раз пометить аннотацией один и тот же элемент. Принимает класс аннотации-контейнера.4)
@Documented
- информация об аннотации будет добавлена в Javadoc классов, где она использована.5)
@Inherited
- даёт возможность наследования аннотации. Если класс помечен аннотацией, имеющей такую мета-аннотацию, то её унаследуют и дочерние классы. Что касается методов — если метод переопределяется, то его нужно аннотировать заново. По умолчанию аннотации не наследуются. Ввиду того, что в Java нет множественного наследования, аннотации над интерфейсами не наследуются, независимо от наличия мета-аннотации @Inherited
.Пожалуй, это вся основная информация по аннотациям в Java.
Материал написан на основе спецификации Java 8 (HTML | PDF).