В 2005 году с приходом версии Java 5 нам стали известны новые сущности под названием аннотации.

Аннотации — это особая форма синтаксических метаданных, которые можно объявить в коде. Они используются для анализа кода при компиляции или во время выполнения программы. Аннотацию можно сравнить с меткой, маркером или указанием для компилятора.

Ты наверняка уже сталкивался с аннотациями. Например, при переопределении метода родительского класса перед самим методом мы пишем @Override. Это и есть аннотация, которая указывает на то, что родительский метод будет переопределен в классе-наследнике.

Синтаксис:


@Override
public int hashCode() {
      return super.hashCode();
}

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

Для понимания работы аннотаций сначала познакомимся с понятием маркерного интерфейса. Необходимость помечать определенным образом класс для выполнения над ним тех или иных действий существовала у Java-разработчиков с момента появления языка.

До Java 5 для этого использовали интерфейс, не похожий даже сам на себя и не соответствующий своему предназначению. Он был без методов, не нес за собой никакого контракта, просто помечал класс для обособления.

Такой интерфейс назывался маркерным. Из названия следует, что его задача — это маркировать классы для JVM, компилятора или какой-либо библиотеки. До сих пор остались некоторые маркерные интерфейсы, например, Serializable. Этот маркер позволяет нам пометить класс, сообщая о том, что его экземпляры можно сериализовать.

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

Эквивалентное использование аннотации и маркерного интерфейса:


@MyAnnotation
public class MyClass {}

public class MyClass implements MarkerInterface {}

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

В случае с интерфейсом мы помечаем класс: даже при неправильном использовании и появлении ошибки она выявится на этапе компиляции и программа не будет запущена.

С аннотациями не все так просто: ошибка выявится уже в рантайме, а это значит, что программа начнет выполнение, но, ожидаемо, не закончит.

Следует отметить, что если нам нужно пометить класс для возможности использования в дальнейшем, его экземпляры надо передавать в определенный метод:


public class MyInteger implements Sum {}
interface Sum {};

public static void main(String[] args) throws IOException {
        increase(new MyInteger());
}
 
public static void increase(Sum count) {
        // TODO
}

Лучше всего здесь подойдет маркерный интерфейс.

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

Давай рассмотрим стандартные аннотации в JDK:

Аннотация Описание Пример
@Override Указывает, что метод переопределяет метод суперкласса или реализует метод абстрактного класса или интерфейса.

@Override
public int hashCode() {
        return super.hashCode();
}
@Deprecated Помечает код как устаревший.

@Deprecated
public abstract void method();
@SuppressWarnings Отключает для аннотированного элемента предупреждения компилятора. Обрати внимание: если необходимо отключить несколько категорий предупреждений, их следует добавить в фигурные скобки, например, @SuppressWarnings ({"unchecked", "cast"}).

public class DocumentsFolder {
   private List documents;

   @SuppressWarnings("unchecked")
public void addDocument(String document) {
            documents.add(document);
   }
}

В этом примере мы пытаемся в методе добавить в список, у которого не определен тип (дженерик). Компилятор предупредит нас об этом. Хоть это и очень полезно, иногда “ворнингов” бывает слишком много, и они очень шумные. В этом случае можно использовать данную аннотацию к методу с указанием параметра-маркера предупреждения компилятора. Маркеров существует очень много,так что необязательно помнить все, обычно IDEA сама подскажет, какой поставить.

Еще пример использования с передаваемыми несколькими параметрами:


@SuppressWarnings({"unchecked", "deprecated"})