Рубрики
Без рубрики

Обзор встроенных аннотаций Java

Откройте для себя встроенные аннотации в Java.

Автор оригинала: Hakan Ozler.

1. Обзор

В этой статье мы поговорим об основной функции языка Java – аннотациях по умолчанию, доступных в JDK.

2. Что Такое Аннотация

Проще говоря, аннотации-это типы Java, которым предшествует символ”@” .

Java имеет аннотации с момента выпуска версии 1.5. С тех пор они сформировали то, как мы разрабатываем наши приложения.

Spring и Hibernate-отличные примеры фреймворков, которые в значительной степени полагаются на аннотации для использования различных методов проектирования.

В принципе, аннотация присваивает дополнительные метаданные исходному коду, к которому она привязана . Добавив аннотацию к методу, интерфейсу, классу или полю, мы можем:

  1. Информируйте компилятор о предупреждениях и ошибках
  2. Манипулирование исходным кодом во время компиляции
  3. Изменение или проверка поведения во время выполнения

3. Встроенные аннотации Java

Теперь, когда мы рассмотрели основы, давайте взглянем на некоторые аннотации, которые поставляются с ядром Java. Во-первых, есть несколько, которые информируют компиляцию:

  1. @Переопределение
  2. @SuppressWarnings
  3. @Устарело
  4. @SafeVarargs
  5. @functional Interface
  6. @Native

Эти аннотации генерируют или подавляют предупреждения и ошибки компилятора. Их последовательное применение часто является хорошей практикой, так как их добавление может предотвратить будущие ошибки программиста.

Аннотация @Override используется для указания на то, что метод переопределяет или заменяет поведение унаследованного метода.

@SuppressWarnings указывает, что мы хотим игнорировать определенные предупреждения из части кода. Аннотация @SafeVarargs также действует на тип предупреждения, связанного с использованием varargs.

Аннотацию @Deprecated можно использовать для пометки API как больше не предназначенного для использования. Кроме того, эта аннотация была модифицирована в Java 9 для представления дополнительной информации об устаревании.

Более подробную информацию обо всем этом вы можете найти в связанных статьях.

3.1. @Functional Interface

Java 8 позволяет нам писать код более функциональным способом.

Интерфейсы одного абстрактного метода являются большой частью этого. Если мы предполагаем, что один и тот ЖЕ интерфейс будет использоваться лямбдами, мы можем дополнительно пометить его как таковой с помощью @functional Interface :

@FunctionalInterface
public interface Adder {
    int add(int a, int b);
}

Например, @Override с помощью методов, @Functional Interface объявляет о наших намерениях с помощью Сумматора .

Теперь, независимо от того, используем ли мы @functional Interface или нет, мы все равно можем использовать Сумматор таким же образом:

Adder adder = (a,b) -> a + b;
int result = adder.add(4,5);

Но, если мы добавим второй метод в Сумматор, тогда компилятор будет жаловаться:

@FunctionalInterface
public interface Adder { 
    // compiler complains that the interface is not a SAM
    
    int add(int a, int b);
    int div(int a, int b);
}

Теперь это было бы скомпилировано без аннотации @functional Interface . Итак, что это нам дает?

Как и @Override , эта аннотация защищает нас от будущих ошибок программиста. Несмотря на то, что законно иметь более одного метода в интерфейсе, это не так, когда этот интерфейс используется в качестве лямбда-цели. Без этой аннотации компилятор сломался бы в десятках мест, где Сумматор использовался в качестве лямбды. Теперь/| он просто врывается Сумматор сам по себе.

3.2. @Native

Начиная с Java 8, в пакете java.lang.annotation появилась новая аннотация под названием Native . Аннотация @Native применима только к полям. Это указывает на то, что аннотированное поле является константой, на которую можно ссылаться из собственного кода . Например, вот как он используется в классе Integer :

public final class Integer {
    @Native public static final int MIN_VALUE = 0x80000000;
    // omitted
}

Эта аннотация также может служить подсказкой для инструментов для создания некоторых вспомогательных заголовочных файлов.

4. Мета-аннотации

Далее, мета-аннотации-это аннотации, которые могут быть применены к другим аннотациям.

Например, эти мета-аннотации используются для настройки аннотаций:

  1. @Цель
  2. @Удержание
  3. @Унаследовано
  4. @Документировано
  5. @Повторяемость

4.1. @Target

Объем аннотаций может варьироваться в зависимости от требований. В то время как одна аннотация используется только с методами, другая аннотация может использоваться с конструктором и объявлениями полей.

Чтобы определить целевые элементы пользовательской аннотации, нам нужно пометить ее @Цель аннотация.

@Target может работать с 12 различными типами элементов . Если мы посмотрим на исходный код @SafeVarargs , то увидим, что он должен быть прикреплен только к конструкторам или методам:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD})
public @interface SafeVarargs {
}

4.2. @Удержание

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

Мы используем аннотацию @Retention , чтобы указать, где в жизненном цикле нашей программы применяется наша аннотация .

Для этого нам нужно настроить @Retention с помощью одной из трех политик хранения:

  1. Политика удержания.ИСТОЧНИК – не виден ни компилятором, ни средой выполнения
  2. Политика удержания.КЛАСС – видимый компилятором
  3. Политика удержания.СРЕДА ВЫПОЛНЕНИЯ – видимая компилятором и средой выполнения

Если нет @Удержание аннотация присутствует в объявлении аннотации, затем политика хранения по умолчанию политика хранения по умолчанию .

Если у нас есть аннотация, которая должна быть доступна во время выполнения:

@Retention(RetentionPolicy.RUNTIME)
@Target(TYPE)
public @interface RetentionAnnotation {
}

Затем, если мы добавим некоторые аннотации к классу:

@RetentionAnnotation
@Generated("Available only on source code")
public class AnnotatedClass {
}

Теперь мы можем поразмыслить над Аннотированным классом , чтобы увидеть, сколько аннотаций сохраняется:

@Test
public void whenAnnotationRetentionPolicyRuntime_shouldAccess() {
    AnnotatedClass anAnnotatedClass = new AnnotatedClass();
    Annotation[] annotations = anAnnotatedClass.getClass().getAnnotations();
    assertThat(annotations.length, is(1));
}

Значение равно 1, потому что @RetentionAnnotation имеет политику хранения RUNTIME , в то время как @Generated | не имеет.

4.3. @Унаследовано

В некоторых ситуациях нам может понадобиться подкласс, чтобы аннотации были привязаны к родительскому классу.

Мы можем использовать @Унаследовано аннотация, чтобы наша аннотация распространялась из аннотированного класса в его подклассы.

Если мы применим @Inherited к нашей пользовательской аннотации, а затем применим ее к Базовому классу :

@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface InheritedAnnotation {
}

@InheritedAnnotation
public class BaseClass {
}

public class DerivedClass extends BaseClass {
}

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

@Test
public void whenAnnotationInherited_thenShouldExist() {
    DerivedClass derivedClass = new DerivedClass();
    InheritedAnnotation annotation = derivedClass.getClass()
      .getAnnotation(InheritedAnnotation.class);
 
    assertThat(annotation, instanceOf(InheritedAnnotation.class));
}

Без @Унаследовано аннотация, вышеприведенный тест будет провален.

4.4. @Документировано

По умолчанию Java не документирует использование аннотаций в Javadoc.

Но мы можем использовать аннотацию @Documented , чтобы изменить поведение Java по умолчанию .

Если мы создадим пользовательскую аннотацию, которая использует @Documented :

@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelCell {
    int value();
}

И примените его к соответствующему элементу Java:

public class Employee {
    @ExcelCell(0)
    public String name;
}

Затем Employee Javadoc покажет использование аннотаций: