Аннотации и рефлексия
Метаданные и код, который умеет изучать код
Иногда программе недостаточно знать только значения объектов. Ей нужно понимать, как разработчик пометил класс или метод, какие у типа есть поля и конструкторы, или какой метод нужно вызвать, хотя его имя стало известно только во время выполнения. Для таких задач в Java есть два тесно связанных механизма: аннотации и рефлексия.
Аннотации добавляют к программе метаданные — информацию о коде. Рефлексия позволяет во время выполнения получить описание классов и их членов, прочитать доступные аннотации и, когда это действительно нужно, динамически обратиться к полю, методу или конструктору. Именно на этой связке построено много инфраструктурного кода и фреймворков.
Что будет внутри раздела
- Основы аннотаций. Разберём, что именно означает запись вида
@Overrideи кто может использовать такую метаинформацию. - Встроенные аннотации. Посмотрим на аннотации, которые уже есть в Java, и на задачи, которые они решают в обычном коде.
- Пользовательские аннотации. Научимся описывать собственные метки и передавать в них значения.
- Retention и Target. Определим, как долго аннотация должна сохраняться и к каким элементам программы её разрешено применять.
- Основы рефлексии. Познакомимся с
Classкак с точкой входа в описание типа во время выполнения. - Class, поля и методы. Научимся получать сведения о полях, методах и конструкторах и различать объявленные и унаследованные члены.
- Динамический доступ через Reflection. Посмотрим, как рефлексия позволяет читать значения, создавать объекты и вызывать методы, когда конкретный член выбирается во время выполнения.
- Ограничения и особенности рефлексии. Разберём, где динамичность помогает, а где ухудшает типобезопасность, сопровождение и границы инкапсуляции.
Сначала мы научимся оставлять метаданные в коде, затем — управлять тем, где и как долго они существуют. После этого перейдём к механизму, который способен увидеть структуру типа во время выполнения, и закончим правилами безопасного использования этой гибкости.
@Deprecated
class OldService {
}
Class<OldService> type = OldService.class;
В небольшом примере уже видны обе стороны раздела: класс помечен метаданными,
а объект Class представляет этот тип во время выполнения.
Дальше разберём каждую часть отдельно.