Автор | Cherry-Peng
Источник | https://blog.csdn.net/xsp_happyboy/article/details/80987484
1 Понятие аннотации
1.1 Официальное определение аннотаций
Сначала взгляните на официальное описание аннотации:
An annotation is a form of metadata, that can be added to Java source code. Classes, methods, variables, parameters and packages may be annotated. Annotations have no direct effect on the operation of the code they annotate.
переводить:
注解是一种能被添加到java代码中的元数据,类、方法、变量、参数和包都可以用注解来修饰。注解对于它所修饰的代码并没有直接的影响。
Из официального описания сделаны следующие выводы:
- Аннотации представляют собой форму метаданных. То есть аннотации — это тип данных, принадлежащий java, аналогичный классам, интерфейсам, массивам и перечислениям.
- Аннотации используются для украшения классов, методов, переменных, параметров, пакетов.
- Аннотации не имеют прямого влияния на измененный код.
1.2 Сфера использования аннотаций
Продолжайте смотреть официальное описание сферы его использования:
Annotations have a number of uses, among them:Information for the complier - Annotations can be used by the compiler to detect errors or suppress warnings.Compiler-time and deployment-time processing - Software tools can process annotation information to generate code, XML files, and so forth.Runtime processing - Some annotations are available to be examined at runtime.
переводить:
注解又许多用法,其中有:为编译器提供信息 - 注解能被编译器检测到错误或抑制警告。编译时和部署时的处理 - 软件工具能处理注解信息从而生成代码,XML文件等等。运行时的处理 - 有些注解在运行时能被检测到。
2 Как настроить аннотации
Основываясь на предыдущем разделе, вы имеете общее представление об аннотациях:Аннотация — это своего рода метка, которая может быть отмечена на ключевых узлах (классах, методах, переменных, параметрах, пакетах) в коде программы, а затем программа может обнаружить эти метки во время компиляции или во время выполнения для выполнения каких-то специальных действий. операции.Таким образом, можно нарисовать основной процесс использования пользовательских аннотаций:
- Первым шагом является определение аннотаций, эквивалентных определению тегов;
- Второй шаг — настроить аннотации — поставить отметку в коде программы, которую необходимо использовать;
- Третий шаг, парсинг аннотаций — теги обнаруживаются во время компиляции или во время выполнения, и выполняются специальные операции.
2.1 Основной синтаксис
Часть объявления типа аннотации:
В Java аннотации похожи на классы, интерфейсы и перечисления, поэтому синтаксис их объявления в основном такой же, но используются другие ключевые слова @interface.В базовой реализации все определенные аннотации автоматически наследуют интерфейс java.lang.annotation.Annotation.
public @interface CherryAnnotation {
}
Часть реализации типа аннотации:
Согласно нашему опыту работы с пользовательскими классами, часть реализации класса — это не что иное, как написание конструкций, свойств или методов. Однако в пользовательской аннотации ее часть реализацииМожно определить только одно: элемент типа аннотации.Давайте посмотрим на его синтаксис:
public @interface CherryAnnotation {
public String name();
int age();
int[] array();
}
Может быть, вы думаете, что это не синтаксис для определения абстрактных методов в интерфейсах? Не волнуйтесь, давайте посмотрим на следующее:
public @interface CherryAnnotation {
public String name();
int age() default 18;
int[] array();
}
увидеть ключевые словаdefaultВсе же? Все еще думаете, что это абстрактный метод?
Аннотации определяют:Элементы типа аннотации!
При определении элементов типа аннотации необходимо учитывать следующие моменты:
- Модификатор доступа должен быть общедоступным, в противном случае он по умолчанию общедоступен;
- Тип элемента может быть только базовым типом данных, строкой, классом, типом перечисления, типом аннотации (отражающим эффект вложенности аннотаций) и однобитным массивом вышеуказанных типов;
- Имя элемента обычно определяется как существительное.Если в аннотации есть только один элемент, укажите имя как значение (используйте его позже, это принесет удобство);
- () — это не место для определения параметров метода, и вы не можете определить какие-либо параметры в круглых скобках, только специальный синтаксис;
- default представляет значение по умолчанию, и значение должно быть таким же, как тип, определенный в пункте 2;
- Если значение по умолчанию отсутствует, это означает, что элементу type должно быть присвоено значение при последующем использовании аннотации.
Видно, что синтаксис элемента типа аннотации очень странный, то есть он имеет характеристики атрибутов (которые можно присваивать) и характеристики методов (с парой скобок). Но этот дизайн имеет смысл.Мы увидим в следующих главах: После того, как аннотация определена,При его использовании манипулируйте типом элемента, как манипулируя свойствами, а при синтаксическом анализе манипулируйте типом элемента, как манипулируя методами.
2.2 Часто используемые мета-аннотации
Самое простое определение аннотации включает только две указанные выше части: 1. Имя аннотации 2. Элемент типа, содержащийся в аннотации. Однако, когда мы использовали собственные аннотации JDK, мы обнаружили, что некоторые аннотации могут быть написаны только для методов (например, @Override), а некоторые могут быть написаны поверх классов (например, @Deprecated). Конечно, есть много подробных определений, так как же эти определения делать? Далее идет мета-аннотация!Мета-аннотация: аннотация, которая специально изменяет аннотацию.Все они специально разработаны для лучшего проектирования деталей пользовательских аннотаций. Мы познакомим вас один за другим.
2.2.1 @Target
Аннотация @Target специально используется для ограничения того, к каким элементам Java можно применить пользовательскую аннотацию. Он использует тип перечисления, определенный следующим образом:
public enum ElementType {
/** 类,接口(包括注解类型)或枚举的声明 */
TYPE,
/** 属性的声明 */
FIELD,
/** 方法的声明 */
METHOD,
/** 方法形式参数声明 */
PARAMETER,
/** 构造方法的声明 */
CONSTRUCTOR,
/** 局部变量声明 */
LOCAL_VARIABLE,
/** 注解类型声明 */
ANNOTATION_TYPE,
/** 包的声明 */
PACKAGE
}
//@CherryAnnotation被限定只能使用在类、接口或方法上面
@Target(value = {ElementType.TYPE,ElementType.METHOD})
public @interface CherryAnnotation {
String name();
int age() default 18;
int[] array();
}
2.2.2 @Retention
Аннотация @Retention, переводится как постоянство, удержание. То есть жизненность, используемая для украшения пользовательских аннотаций. Жизненный цикл аннотации состоит из трех этапов: 1. этап исходного файла Java, 2. этап компиляции в файл класса, 3. этап выполнения. Три фазы также определяются с использованием типа перечисления RetentionPolicy:
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
* (注解将被编译器忽略掉)
*/
SOURCE,
/**
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
* (注解将被编译器记录在class文件中,但在运行时不会被虚拟机保留,这是一个默认的行为)
*/
CLASS,
/**
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
* (注解将被编译器记录在class文件中,而且在运行时会被虚拟机保留,因此它们能通过反射被读取到)
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
Давайте подробнее:
- Если аннотация определена как RetentionPolicy.SOURCE, она будет ограничена исходным файлом Java, тогда аннотация не будет ни участвовать в компиляции, ни играть какую-либо роль во время выполнения, эта аннотация имеет тот же эффект, что и аннотация, может быть видна только люди, которые читают файлы Java;
- Если аннотация определена как RetentionPolicy.CLASS, она будет скомпилирована в файл класса, тогда компилятор может выполнить некоторые действия по обработке в соответствии с аннотацией во время компиляции, но JVM (виртуальная машина Java) будет игнорировать ее во время выполнения, мы текущий период не может быть прочитан;
- Если аннотация определена как RetentionPolicy.RUNTIME, то аннотацию можно загрузить в объект Class на этапе загрузки во время выполнения. Затем на этапе выполнения программы мы можем получить эту аннотацию посредством отражения и выполнить различные сегменты кода программы, определив, есть ли эта аннотация или значение атрибута в этой аннотации. Почти все пользовательские аннотации в нашей фактической разработке используют RetentionPolicy.RUNTIME;
- По умолчанию используются пользовательские аннотации RetentionPolicy.CLASS.
2.2.3 @Documented
Аннотация @Documented используется для указания возможности создания пользовательских аннотаций в документах JavaDoc вместе с определенными файлами Java.
2.2.4 @Inherited
Аннотация @Inherited указывает, что если пользовательская аннотация написана в части объявления родительского класса, часть объявления подкласса также может автоматически иметь аннотацию. Аннотация @Inherited работает только для тех пользовательских аннотаций, @Target которых определен как ElementType.TYPE.
3 Настройка и использование пользовательских аннотаций
Просмотрите процесс использования аннотаций:
- Первым шагом является определение аннотаций, эквивалентных определению тегов;
- Второй шаг — настроить аннотации — поставить отметку в коде программы, которую нужно использовать;
- Третий шаг, парсинг аннотаций — теги обнаруживаются во время компиляции или во время выполнения, и выполняются специальные операции.
Пока мы выполнили только первый шаг, далее будем учиться второму шагу, настройке аннотации, как ее настроить в другом классе.
3.1 Использование аннотаций в конкретных классах Java
Во-первых, определите аннотацию и простой класс Java для оформления аннотации.
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD})
@Documented
public @interface CherryAnnotation {
String name();
int age() default 18;
int[] score();
}
public class Student{
public void study(int times){
for(int i = 0; i < times; i++){
System.out.println("Good Good Study, Day Day Up!");
}
}
}
При простом анализе:
- @Target CherryAnnotation определяется как ElementType.METHOD, тогда его следует писать над определением метода, то есть: выше public void study(int times);
- Поскольку у нас есть элементы типа аннотации, определенные в CherryAnnotation, а некоторые элементы не имеют значения по умолчанию, это требует, чтобы мы использовали () после имени тега и внутри () с «имя элемента = значение элемента». Заполните все элементы типа аннотации без значения по умолчанию по одному в виде (также можно заполнить переназначение, если есть значения по умолчанию), разделенные «,» посередине;
Таким образом, окончательная письменная форма выглядит следующим образом:
public class Student {
@CherryAnnotation(name = "cherry-peng",age = 23,score = {99,66,77})
public void study(int times){
for(int i = 0; i < times; i++){
System.out.println("Good Good Study, Day Day Up!");
}
}
}
3.2 Специальный синтаксис
Специальный синтаксис один:
Если в самой аннотации нет элемента типа аннотации, вы можете опустить () при использовании аннотации и написать ее напрямую как: @имя аннотации, что эквивалентно стандартному синтаксису @имя аннотации()!
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE})
@Documented
public @interface FirstAnnotation {
}
//等效于@FirstAnnotation()
@FirstAnnotation
public class JavaBean{
//省略实现部分
}
Второй специальный синтаксис:
Если сама аннотация имеет только один элемент типа аннотации и он именованный, то при использовании аннотации можно напрямую использовать: @имя аннотации (значение аннотации), что эквивалентно: @имя аннотации (значение = значение аннотации)
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE})
@Documented
public @interface SecondAnnotation {
String value();
}
//等效于@ SecondAnnotation(value = "this is second annotation")
@SecondAnnotation("this is annotation")
public class JavaBean{
//省略实现部分
}
Специальное использование три:
Если элемент типа аннотации в аннотации является типом массива, и при его использовании необходимо заполнить только одно значение, то при использовании аннотации его можно записать напрямую в виде: @имя аннотации (имя типа = значение типа), Эквивалентно стандартному написанию: @ имя аннотации (имя типа = {тип значения})!
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE})
@Documented
public @interface ThirdAnnotation {
String[] name();
}
//等效于@ ThirdAnnotation(name = {"this is third annotation"})
@ ThirdAnnotation(name = "this is third annotation")
public class JavaBean{
//省略实现部分
}
Специальное использование четыре:
Если @Target аннотации определен как Element.PACKAGE, то аннотация настраивается в package-info.java и не может быть настроена непосредственно в коде пакета класса.
4 Анализ пользовательских аннотаций во время выполнения
Эта глава является ядром использования аннотаций, вы можете понять это, прочитав эту главу.Как обнаружить аннотации во время работы программы и выполнить ряд специальных операций!
4.1 Отзыв о сохранении аннотаций
Прежде всего, давайте рассмотрим ранее настроенную аннотацию @CherryAnnotation и настроим ее на классе Student Код выглядит следующим образом:
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD})
@Documented
public @interface CherryAnnotation {
String name();
int age() default 18;
int[] score();
}
package pojos;
public class Student {
@CherryAnnotation(name = "cherry-peng",age = 23,score = {99,66,77})
public void study(int times){
for(int i = 0; i < times; i++){
System.out.println("Good Good Study, Day Day Up!");
}
}
}
Три этапа сохранения аннотаций:
- Этап исходного файла Java;
- Скомпилировать в файл класса stage;
- фаза выполнения.
Только когда сила удержания аннотации находится в фазе выполнения, то есть когда аннотация изменена с помощью @Retention(RetentionPolicy.RUNTIME), аннотация может быть обнаружена, и во время работы JVM может быть выполнен ряд специальных операций. .
4.2 Операция отражения для получения аннотаций
Поэтому, чтобы уточнить наши цели:Изучение и использование содержимого во время компиляции (аннотаций конфигурации во время компиляции) во время выполнения требует использования технологии души в Java — рефлексии!
public class TestAnnotation {
public static void main(String[] args){
try {
//获取Student的Class对象
Class stuClass = Class.forName("pojos.Student");
//说明一下,这里形参不能写成Integer.class,应写为int.class
Method stuMethod = stuClass.getMethod("study",int.class);
if(stuMethod.isAnnotationPresent(CherryAnnotation.class)){
System.out.println("Student类上配置了CherryAnnotation注解!");
//获取该元素上指定类型的注解
CherryAnnotation cherryAnnotation = stuMethod.getAnnotation(CherryAnnotation.class);
System.out.println("name: " + cherryAnnotation.name() + ", age: " + cherryAnnotation.age()
+ ", score: " + cherryAnnotation.score()[0]);
}else{
System.out.println("Student类上没有配置CherryAnnotation注解!");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
объяснять:
- Если аннотация, которую мы хотим получить, настроена на метод, то нам нужно получить ее из объекта «Метод»; если она настроена на атрибут, нам нужно получить ее из объекта «Поле», соответствующего атрибуту; если она настроена для типа нам нужно получить его из объекта Field.Get the Class object. Короче говоря, кто бы это ни был, получай от кого бы то ни было!
- isAnnotationPresent(Class annotationClass)Метод заключается в том, чтобы специально определить, настроена ли указанная аннотация для элемента;
- getAnnotation(Class annotationClass)Метод заключается в получении указанной аннотации к элементу. Затем вызовите метод элемента типа аннотации аннотации, чтобы получить данные значения во время настройки;
- Также есть метод на объекте отраженияgetAnnotations(), этот метод может получить все аннотации, настроенные для объекта. Он вернет нам массив аннотаций.Следует отметить, что тип массива имеет тип Annotation, который является интерфейсом из пакета java.lang.annotation.
Если статья была вам полезна, не забудьте поставить лайк и подписаться~
Приглашаю всех обратить внимание на мою официальную учетную запись: Любите ИТ и публикуйте технические статьи каждый день, чтобы все могли учиться и ссылаться на них.