Аннотации предназначены в основном для использования в инструментальных средствах разработки и развертывания прикладных программ на Java.
Но если они задают правило удержания RUNTIME, то могут быть опрошены во время выполнения в любой программе нa Java с помощью рефлексии.
Рефлексия — это языковое средство для получения сведений о классе во время выполнения программы.
Прикладной программный интерфейс (API) для рефлексии входит в состав пакета jаva.lang.reflect.
Пользоваться рефлексией можно самыми разными способами. Обратимся к нескольким примерам применения рефлексии, имеющим отношение к аннотациям.
Первый шаг с целью воспользоваться рефлексией состоит в получении объекта типа Class. Этот объект представляет класс, аннотацию которого требуется получить.
А Class относится к числу встроенных в Java классов и определен в пакете java.lang.
Имеются разные способы получения объекта типа Class. Самый простой из них — вызвать метод getClass(), определенный в классе Object.
Его общая форма приведена ниже. Этот метод возвращает объект типа Class, который представляет вызывающий объект.
1 |
final Class<?> getClass() |
Обратите внимание на знаки <?>, следующие за именем Class в приведенном выше объявлении метода getClass(). Это обозначение имеет отношение к обобщениям в Java.
Имея в своем распоряжении объект типа Class, можно воспользоваться его методами для получения сведений о различных элементах, объявленных в классе, включая и его аннотацию.
Если требуются аннотации, связанные с определенны мэлементом, объявленным в классе, сначала следует получить объект, представляющий этот элемент.
Кто нибудь кодит на PHP? Как там обстоят дела с таким инструментом как рефлексия? У меня знакомый делает шаблоны под WordPress типа ThemeForest WoodMart говорит что никогда не использовал еще.
Например, класс Class предоставляет (среди прочего) методы getMethod(), getField() и getConstructor(), возвращающие сведения о методе, поле и конструкторе соответственно. Эти методы возвращают объекты типа Method, Field и Constructor.
Чтобы понять этот процесс, рассмотрим в качестве примера получение аннотаций, связанных с методом. Для этого сначала получается объект типа Class, представляющий класс, затем вызывается метод getMethod() для этого объекта с указанным именем искомого метода. У метода getMethod() имеется следующая общая форма:
1 |
Method getMethod(String имя_метода, Class<?> ... типы_параметров) |
Имя искомого метода передается в качестве аргумента имя_метода. Если этот метод принимает аргументы, то объекты типа Class, представляющие их типы, должны быть также указаны в качестве аргумента типы_параметров.
Обратите внимание на то, что аргумент типы_параметров представляет собой список аргументов переменной длины.
Это позволяет задать столько типов параметров, сколько требуется, в том числе и не указывать их вообще. Метод getMethod() возвращает объект типа Method, который представляет метод.
Если метод не удается найти, то генерируется исключение типа NoSuchMethodException.
Из объекта типа Class, Method, Field или Constructor можно получить конкретные аннотации, связанные с этим объектом, вызвав метод getAnnotation(). Его общая форма приведена ниже:
1 |
<A extends Annotation> getAnnotation(Class<A> тип_аннотации) |
Здесь параметр тип_аннотации обозначает объект типа Class, представляющий требующуюся аннотацию. Этот метод возвращает ссылку на аннотацию.
Используя эту ссылку, можно получить значения, связанные с членами аннотации. Метод getAnnotation() возвращает пустое значение null, если аннотация не найдена.
В этом случае у искомой аннотации отсутствует аннотация @Retention, устанавливающая правило удержания RUNTIME.
Ниже приведен пример программы, подытоживающий все сказанное выше. В этой программе рефлексия применяется для вывода аннотации, связанной с конкретным методом.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
import java.lang.annotation.*; import java.lang.reflect.*; // Объявление типа аннотации @Retention(RetentionPolicy.RUNTIME) @interface MyAnno { String str(); int val(); } class Meta { // аннотировать метод @MyAnno(str = "Пример аннотации", val = 32100) public static void myMeth() { Meta ob = new Meta(); // получить аннотацию из метода // и вывести значения ее членов try { // сначала получить объект типа Class, // представляющий данный класс Class<?> c = ob.getClass(); // затем получить объект типа Method, // представляющий данный метод Method m = c.getMethod("myMeth"); // далее получить аннотацию для данного класса MyAnno anno = m.getAnnotation(MyAnno.class); // и наконец, вывести значения членов аннотации System.out.println(anno.str() + " " + anno.val()); } catch (NoSuchMethodException exc) { System.out.println("Метод не найден."); } } public static void main(String args[]) { myMeth(); } } |
Ниже приведен результат, выводимый данной программой.
1 2 3 4 |
pro-java.ru@admin:~$ javac reflection.java pro-java.ru@admin:~$ java Meta Пример аннотации 32100 pro-java.ru@admin:~$ |
В этой программе рефлексия применяется, как описано выше, для полученияи вывода значений переменных str и val из аннотации MyAnno, связанной с методом myMeth() из класса Meta.
Здесь следует обратить особое внимание на следующее. Во-первых, это выражение MyAnno.class в следующей строке кода:
1 |
MyAnno anno = m.getAnnotation(MyAnno.class); |
Это выражение вычисляется как объект Class, относящийся к типу MyAnno, т.е. к искомой аннотации, и называется литералом класса.
Такое выражение можно использовать всякий раз, когда требуется объект Class известного класса. Например, в следующем операторе получается объект Class для класса Meta:
1 |
Class<?> c = Meta.class; |
Безусловно, такой подход годится лишь в том случае, если заранее известноимя класса искомого объекта, что возможно далеко не всегда.
В общем, литерал класса можно получить для классов, интерфейсов, примитивных типов и массивов. Напомним, что синтаксис <?> имеет отношение к обобщениям в Java.
И во-вторых, это способ получения значений, связанных с переменными str и val, когда они выводятся в следующей строке кода:
1 |
System.out.println(anno.str() + " " + anno.val()); |
Обратите внимание на то, что для обращения к ним применяется синтаксис вызова методов. Тот же самый подход применяется всякий раз, когда требуется получить член аннотации.