Создание и применение аннотаций

Последнее обновление: 01.11.2025

Создание собственных аннотаций

Хотя в языке Java, во фреймворках на этом языке есть различные аннотации для разных ситуаций, но Java также позволяет создавать свои собственные аннотации. Каждая аннотация определяется с помощью ​​интерфейса аннотации - с помощью ключевого слова @interface, после которого указывается имя аннотации. @interface создает интерфейс Java:

// объявление аннотации под названием MyAnnotation
@interface MyAnnotation {

}

После имени аннотации (как и в случае с интерфейсами) идут фигурные скобки, внутри которых размещаются элементы аннотации. В данном случае аннотация называется "MyAnnotation" и не содержит никаких элементов.

Все интерфейсы аннотаций неявно расширяют интерфейс java.lang.annotation.Annotation, который является обычным интерфейсом. Однако расширять интерфейсы аннотаций или реализовать их в своих классах нельзя. Вместо этого инструменты обработки исходного кода и виртуальная машина при необходимости сами автоматически генерируют необходимые прокси-классы и объекты.

При создании аннотации часто используются так называемые мета-аннотации (аннотации для аннотаций):

  • @Retention: определяет политику хранения.

  • @Target: указывает, к каким элементам кода можно применять аннотацию (класс, метод, поле, параметр и т.д.).

  • @Documented: указывает, что аннотация должна быть включена в генерируемую Javadoc-документацию.

  • @Inherited: указывает, что аннотация, примененная к классу, будет наследоваться его подклассами.

  • @Repeatable: позволяет применять одну и ту же аннотацию к одному элементу несколько раз.

Далее мы рассмотрим некоторые из этих мета-аннотаций. А пока посмотрим, как мы можем применить нашу аннотацию.

@interface MyAnnotation{}

@MyAnnotation
class Thing{
    @MyAnnotation String name;
}

Здесь аннотация MyAnnotation применяется к объявлениям - к классу Thing и его полю name. Причем аннотация сама по себе и ее применение ничего не делают, мы можем использовать этот класс как обычный класс:

// объявляем аннотацию
@interface MyAnnotation{}

// применяем аннотацию к классу Thing
@MyAnnotation
class Thing{ }

class Program{
 
    public static void main(String[] args) throws Exception{
          
        Thing thing = new Thing();
        System.out.println(thing);
    }
}

Стоит отметить, что по умолчанию аннотация может использоваться с любыми объявлениями, но не с параметрами типа (в обобщениях) и использованием типов. Для более детальной настройки применения аннотации применяется мета-аннотация @Target.

@Target

Мета-аннотация @Target определяет, к каким элементам кода можно применять аннотацию. Ее значение представляет массив объектов ElementType, которые и определяют элементы для применения аннотации:

  • ElementType.ANNOTATION_TYPE: объявления типов аннотаций

  • ElementType.MODULE: модули

  • ElementType.PACKAGE: пакеты

  • ElementType.TYPE: классы (включая перечисления) и интерфейсы (включая типы аннотаций)

  • ElementType.METHOD: методы

  • ElementType.CONSTRUCTOR: конструкторы

  • ElementType.FIELD: поля (включая константы перечисления)

  • ElementType.PARAMETER: параметры метода или конструктора

  • ElementType.RECORD_COMPONENT: компоненты record-классов

  • ElementType.LOCAL_VARIABLE: локальные переменные

  • ElementType.TYPE_PARAMETER: параметры типы

  • ElementType.TYPE_USE: использование типа

Например:

@Target({ElementType.FIELD, ElementType.RECORD_COMPONENT, ElementType.TYPE})
@interface MyAnnotation

Здесь аннотация MyAnnotation может применться к полям, типам (классам и интерфейсам) и компонентам классов record. Например:

@MyAnnotation
class Thing{
    @MyAnnotation String name;
}

Но, например, к методам и другим компонентам такая аннотация применяться не может.

Аннотация без ограничения @Target может использоваться с любыми объявлениями, но не с параметрами типа и использованием типов.

Элементы аннотаций

Аннотация может содержать элементы, которые фактически являются методами. Причем эти методы не могут иметь параметров, не могут быть обобщенными, а также не могут в объявлении содержать выражения throws. Например:

@interface MyAnnotation {

    // элементы аннотации
    String value();
    int count();
}

В данном случае аннотация MyAnnotation имеет два элемента: value (представляет строку) и count (представляет число).

При применении аннотации нам надо передать этим элементам некоторые значения:

@interface MyAnnotation {

    // элементы аннотации
    String value();
    int count();
}

@MyAnnotation(value="Thing", count=1)
class Thing{ }

Значения для элементов аннотаций передаются после названия аннотации в скобках через запятую в виде название_элемента = значение_элемента. В какой-то степени это похоже на вызов конструктора класса.

Значения по умолчанию для элементов аннотаций

Элементы аннотаций могут иметь значение по умолчанию. Для его установки после метода и перед значением по умолчанию указывается ключевое слово default. Например:

@interface MyAnnotation {

    // элементы аннотации со значениями по умолчанию
    String value() default "default value";
    int count() default 0;
}

Если элементы аннотации имеют значения по умолчанию, то при применении аннотации для этих элементов можно не передавать значения:

@interface MyAnnotation {

    // элементы аннотации со значениями по умолчанию
    String value() default "DefaultValue";
    int count() default 0;
}

@MyAnnotation(value="Type A", count=2)
class TypeA{ }

@MyAnnotation(value="Type B")  // count = 0
class TypeB{ }

@MyAnnotation(count=1)      // value = DefaultValue
class TypeC{ }

@MyAnnotation               // value = DefaultValue, count = 0
class TypeD{ }

Если элемент аннотации представляет массив, то в качестве значения по умолчанию указываются внутри фигурных скобок:

@interface MyAnnotation {
    String[] addresses() default {"address1@humail.com", "address2@humail.com"};
    String[] posts() default {};    // пустой массив
}

Значения по умолчанию не сохраняются вместе с аннотацией, а вычисляются динамически.

@Retention

Мета-аннотация @Retention указывает, где можно получить доступ к аннотации, то есть по сути то, как долго аннотация "живет". Эта аннотация может принимать одно из трех значений перечисления RetentionPolicy:

  • RetentionPolicy.SOURCE: аннотация существует только в исходном коде и отбрасывается компилятором. Используется, например, для инструментов анализа кода или кодогенерации

  • RetentionPolicy.CLASS: аннотация сохраняется в файле .class (в байт-коде), но недоступна во время выполнения. Это значение по умолчанию.

  • RetentionPolicy.RUNTIME: аннотация сохраняется в файле .class, но в отличие от предыдущего варианта аннотация доступна во время выполнения через рефлексию (reflection). (Это самый распространенный тип для фреймворков, например, Spring или JUnit, которые анализируют классы во время работы программы)

Пример применения мета-аннотации:

@Retention(RetentionPolicy.RUNTIME)     // Аннотация доступна во время выполнения
@Target(ElementType.TYPE)             // Аннотация применяется к типам
@interface MyAnnotation {

    String value() default "DefaultValue";
}
Помощь сайту
Юмани:
410011174743222
Номер карты:
4048415020898850
Morty Proxy This is a proxified and sanitized view of the page, visit original site.