В предыдущей статье мы говорили о том, что такое аннотации и как пользоваться готовыми аннотациями в Java. Но Java также дает возможность создавать собственные аннотации для улучшения кода. Чтобы сгенерировать любую пользовательскую аннотацию, необходимо использовать мета-аннотации. В этой статье объясняется, как создавать мета- и пользовательские аннотации и украшать ими объекты.
Пользовательские аннотации
Наряду со множеством предопределенных аннотаций в Java можно определять и собственные пользовательские аннотации. Самодельные аннотации дают следующие преимущества.
- Сокращают затраты на написание кода, добавляя к методам поведение по умолчанию.
- Добавляют настраиваемое поведение классам и интерфейсам.
- Экономят усилия на написании XML-дескрипторов и интерфейсов-маркеров.
Чтобы определить любую пользовательскую аннотацию, сначала нужно объявить ее с помощью тега @interface
. Затем мы определяем цель и область применения через мета-аннотации. Работа с мета-аннотациями (@Retention
, @Target
, @Inherited
) объясняется во второй половине этой статьи. Пользовательские аннотации могут быть определены на трех уровнях:
- уровень класса;
- уровень поля;
- уровень метода.
Уровень класса
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.Type)
public @interface CustomAnnotation{ ... }
Приведенная выше пользовательская аннотация CustomAnnotation
создана с политикой доступности во времени выполнения, и ее можно применять ко всем классам. Поскольку у нее нет методов, она служит простым маркером для обозначения нужных классов.
Здесь следует отметить, что любая пользовательская аннотация на уровне класса не может содержать никаких параметров и не должна вызывать никаких исключений. Кроме того, типы возвращаемых значений ограничены примитивами, строками, классами, перечислениями, аннотациями и их массивами, а значение по умолчанию не может быть null
.
Уровень поля
Аналогично уровню класса, можно определять аннотации на уровне полей и ограничивать область действия.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface CustomAnnotation{ ... }
Уровень метода
Мы также можем объявлять аннотацию с доступностью во время выполнения, чтобы применять ее к методам классов:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CustomAnnotation{ ... }
Применение пользовательских аннотаций
Вот пример, демонстрирующий использование пользовательских аннотаций.
Речь идет о двух классах: автомобиле Car
и двигателе Engine
. Предположим, что BasicEngine
должен применяться ко всем типам автомобилей. В этом случае можно разработать пользовательскую аннотацию, такую как @BasicEngine
, и аннотировать все виды реализаций автомобиля (например, хэтчбеки, спортивные автомобили, седаны и т.д.) через BasicEngine
.
Пользовательская аннотация класса (интерфейса):
import java.lang.annotation.*;
@Inherited
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface BasicEngine {
String mileage() default "20";
String fuelType() default "Gasoline";
}
Класс, использующий пользовательскую аннотацию (нет необходимости в импорте):
@BasicEngine(bId="30", bName="BioDiesel")
public class Car {
String make;
String model; public Car(String make, String model){
this.make = make;
this.model = model;
}
public void getCarDetails(){
System.out.println("Car Manufacturer: " + make);
System.out.println("Car Model: " + model);
}
}
Класс водителя (Driver) для проверки вышеизложенного:
import java.lang.annotation.Annotation; public class TestCustomAnnotationBasicEngine { public static void main(String[] args) throws Exception{ Car car = new Car("32", "Diesel"); car.getCarDetails(); Class carClass = car.getClass(); Annotation testAnn = carClass.getAnnotation(BasicEngine.class); BasicEngine engine = (BasicEngine)testAnn; System.out.println("Mileage: " + engine.mileage()); System.out.println("Fuel Type: " + engine.fuelType()); } }
Мета-аннотации
Мета-аннотации — это аннотации, применяемые к другим аннотациям для увеличения масштаба. Это очень важно, поскольку позволяет описывать аннотации, используя другие аннотации, и комбинировать аннотации.
В схему языка Java включены следующие важные мета-аннотации.
@Inherited
По умолчанию аннотация не может наследовать от своего суперкласса. Однако, если нужно наследовать аннотацию от суперкласса к подклассу, используется аннотация @Inherited
.
@Inherited public @interface CustomAnnotation { ... } @CustomAnnotation public class ParentClass { ... } public class ChildClass extends ParentClass { ... }
Здесь дочерний класс ChildClass
автоматически получает пользовательскую аннотацию CustomAnnotation
, поскольку наследуется от родительского класса ParentClass
. Дочерний класс может вызывать любую функциональность CustomAnnotation
.
@Target
Области действия аннотаций основаны на требованиях метода или файла, таких как конструкторы или объявления. Мы можем ограничить применение аннотации к определенным целям с помощью аннотации @Target
.
@Target(ElementType.METHOD)
public @interface CustomAnnotation{ ... }
В приведенном выше коде пользовательская аннотация CustomAnnotation
ограничена только методами, т.е. поля, пакеты и т.д. не будут аннотироваться с ее помощью.
Аннотация может быть использована для любого элемента, если целевой тип не определен.
@Retention
Мета-аннотация @Retention
указывает уровень, до которого будет доступна аннотация.
Существует три уровня, относительно которых Java позволяет определять политики хранения.
RetentionPolicy.SOURCE
— доступно на уровне исходного кода и игнорируется компилятором.RetentionPolicy.CLASS
— доступно компилятору во время компиляции и игнорируется JVM.RetentionPolicy.RUNTIME
— доступно для JVM.
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomAnnotation{ ... }
В заключение, аннотации — это удобный инструмент, который предоставляет Java. Их изучение очень помогает в том, чтобы стать более профессиональным разработчиком!
Читайте также:
- Плюсы и минусы программирования на Java
- Синхронизация в Java.
- Учимся избегать null-значений в современном Java.
Читайте нас в Telegram, VK и Яндекс.Дзен
Перевод статьи Utkarsh Jain: Java: Creating and Using Custom Annotations