Аннотации и рефлексия

Базовый Java
≈ 2 мин чтения

Метаданные и код, который умеет изучать код

Иногда программе недостаточно знать только значения объектов. Ей нужно понимать, как разработчик пометил класс или метод, какие у типа есть поля и конструкторы, или какой метод нужно вызвать, хотя его имя стало известно только во время выполнения. Для таких задач в Java есть два тесно связанных механизма: аннотации и рефлексия.

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

Что будет внутри раздела

  • Основы аннотаций. Разберём, что именно означает запись вида @Override и кто может использовать такую метаинформацию.
  • Встроенные аннотации. Посмотрим на аннотации, которые уже есть в Java, и на задачи, которые они решают в обычном коде.
  • Пользовательские аннотации. Научимся описывать собственные метки и передавать в них значения.
  • Retention и Target. Определим, как долго аннотация должна сохраняться и к каким элементам программы её разрешено применять.
  • Основы рефлексии. Познакомимся с Class как с точкой входа в описание типа во время выполнения.
  • Class, поля и методы. Научимся получать сведения о полях, методах и конструкторах и различать объявленные и унаследованные члены.
  • Динамический доступ через Reflection. Посмотрим, как рефлексия позволяет читать значения, создавать объекты и вызывать методы, когда конкретный член выбирается во время выполнения.
  • Ограничения и особенности рефлексии. Разберём, где динамичность помогает, а где ухудшает типобезопасность, сопровождение и границы инкапсуляции.

Сначала мы научимся оставлять метаданные в коде, затем — управлять тем, где и как долго они существуют. После этого перейдём к механизму, который способен увидеть структуру типа во время выполнения, и закончим правилами безопасного использования этой гибкости.

@Deprecated
class OldService {
}

Class<OldService> type = OldService.class;

В небольшом примере уже видны обе стороны раздела: класс помечен метаданными, а объект Class представляет этот тип во время выполнения. Дальше разберём каждую часть отдельно.