Detailed explanation of java custom annotations

1: The concept of annotation

1.1 Official definition of annotation

First, take a look at the official description of annotations:

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.

translate:

Annotations are metadata that can be added to Java code. Classes, methods, variables, parameters, and packages can all be modified with annotations. Annotations have no direct impact on the code they modify. 

The following conclusions can be drawn from the official description:

  1. Annotations are a form of metadata (metadata: use data to describe data. In Java, they are represented by annotations). That is, annotations are a data type belonging to Java, similar to classes, interfaces, arrays, and enumerations (they are at the same level).
  2. Annotations are used to modify classes, methods, variables, parameters, and packages.
  3. Annotations do not have a direct impact on the code they modify. 

1.2 Scope of use of annotations 

Continue to look at the official description of its scope of use:

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.

translate:

Annotations have many uses, including: providing information to the compiler  - annotations can be used by the compiler to detect errors or suppress warnings. Compile-time and deployment-time processing  - Software tools can process annotation information to generate code, XML files, etc. Runtime processing  - Some annotations can be detected at runtime. 

2: How to customize annotations 

Based on the previous section, we have a basic understanding of annotations: Annotations are actually a kind of mark. These marks can be placed on key nodes (classes, methods, variables, parameters, packages) in the program code, and then the program is compiled These tags can be detected at runtime or runtime to perform some special operations . Therefore, the basic process for using custom annotations can be drawn:

  • The first step is to define annotations - equivalent to defining tags;
  • The second step is to configure the annotation - put the mark in the program code that needs to be used;
  • The third step is to parse the annotation - detect the mark at compile time or runtime, and perform special operations.

 

 2.1 Basic syntax

 2.1.1 Declaration part of annotation type:

Annotations in Java are similar to classes, interfaces, and enumerations, so their declaration syntax is basically the same, but the keywords used are different @interface. In the underlying implementation, all defined annotations will automatically inherit the java.lang.annotation.Annotation interface

public @interface CherryAnnotation {
}

2.1.2 Implementation part of annotation type:

According to our experience in custom classes, the implementation part of the class is nothing more than writing constructs, properties or methods. However, in custom annotations, the implementation part can only define one thing: annotation type element . Let's take a look at its syntax:

public @interface CherryAnnotation {
	public String name();
	int age();
	int[] array();
}

Maybe you will think that this is not the syntax for defining abstract methods in interfaces? Don’t worry, let’s take a look at this:

public @interface CherryAnnotation {
	public String name();
	int age() default 18;
	int[] array();
}

See the keyword default? Do you still think it is an abstract method?

What is defined in the annotation is: annotation type element!

When defining annotation type elements, you need to pay attention to the following points:

(1) The access modifier must be public, and it defaults to public if not written;
(2) The type of this element can only be part of the data type, String, Class, enumeration type, annotation type (reflecting the nesting effect of annotations) and A one-bit array of the above type;
(3) The name of the element is generally defined as a noun. If there is only one element in the annotation, please name it value (it will be convenient to use later); (4) () is not a definition
method Where parameters are used, no parameters can be defined in parentheses, it is just a special syntax; (
5) default represents the default value, and the value must be consistent with the type defined in point 2;
(6) If there is no default value, it represents subsequent use This type of element must be assigned a value when annotating.

It can be seen that the syntax of annotation type elements is very strange. It has the characteristics of attributes (can be assigned values) and methods (with a pair of brackets). But this design makes sense. We can see in the following chapters: after the annotation is defined, the element type is manipulated like an attribute when used, and the element type is manipulated like a method when parsed .

2.2 Commonly used meta-annotations

A most basic annotation definition only includes the above two parts: 1. The name of the annotation; 2. The type elements contained in the annotation. However, when we used the JDK's own annotations, we found that some annotations can only be written on methods (such as @Override); some can be written on classes (such as @Deprecated). Of course, there are many detailed definitions besides this, so how should these definitions be made? Next, it’s time for meta-annotation to appear!
Meta-annotation: an annotation that specifically modifies annotations . They are specially designed to better design the details of custom annotations. We will introduce each one for you.

2.2.1 @Target

The @Target annotation is specifically used to limit which Java elements a custom annotation can be applied to. It uses an enumeration type defined as follows:

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 annotation, translated as endurance and retention. That is, the vitality used to modify custom annotations.
The life cycle of annotations has three stages: 1. Java source file stage; 2. Compiled to class file stage; 3. Runtime stage. The RetentionPolicy enumeration type is also used to define three stages:

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
}

Let’s explain it in detail

(1) If an annotation is defined as RetentionPolicy.SOURCE, it will be limited to the Java source file, then this annotation will neither participate in compilation nor play any role during runtime. This annotation is the same as an annotation. The effect can only be seen by people who read the Java file;
(2) If an annotation is defined as RetentionPolicy.CLASS, it will be compiled into the Class file, then the compiler can do some processing actions based on the annotation during compilation , but the JVM (Java Virtual Machine) will ignore it at runtime, and we cannot read it at runtime;
(3) If an annotation is defined as RetentionPolicy.RUNTIME, then this annotation can be loaded during the loading phase of the runtime. in the Class object. Then during the program running phase, we can get this annotation through reflection, and execute different program code segments by judging whether there is this annotation or the value of the attribute in this annotation. Almost all custom annotations in our actual development use RetentionPolicy.RUNTIME;
(4) By default, custom annotations use RetentionPolicy.CLASS.

2.2.3 @Documented

The @Documented annotation is used to specify whether custom annotations can be generated into the JavaDoc document along with the defined java file.

2.2.4 @Inherited

The @Inherited annotation specifies that if a custom annotation is written in the declaration part of the parent class, the declaration part of the subclass can also automatically have the annotation. The @Inherited annotation only works for custom annotations where @Target is defined as ElementType.TYPE.

Three: Configuration and use of custom annotations

Let’s review the process of using annotations:

  • The first step is to define annotations - equivalent to defining tags;
  • The second step is to configure the annotation - put the mark in the program code that needs to be used;
  • The third step is to parse the annotation - detect the mark at compile time or runtime, and perform special operations.

So far we have only completed the first step. Next we will learn the second step, configuring annotations and how to configure it in another class.

3.1 Using annotations on specific Java classes 

First, define an annotation and a simple Java class for annotation modification

@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!");
        }
    }
}

A brief analysis:

(1) CherryAnnotation’s @Target is defined as ElementType.METHOD, then its writing position should be above the method definition, that is: above public void study (int times); (2) Since
we have annotation types defined in CherryAnnotation elements, and some elements do not have default values, which requires us to put () after the tag name when using it, and fill in all the elements without default values ​​one by one in the form of "element name = element value" within () Annotation type elements (those with default values ​​can also be filled in and reassigned), separated by "," in the middle;

So the final written form is as follows:

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 Special syntax

3.2.1 Special syntax 1:

If the annotation itself does not have an annotation type element, you can omit () when using the annotation and write it directly as: @annotation name, which is equivalent to the standard syntax @annotation name ()!

@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE})
@Documented
public @interface FirstAnnotation {
}
//等效于@FirstAnnotation()
@FirstAnnotation
public class JavaBean{
	//省略实现部分
}

3.2.2 Special syntax 2:

If the annotation book itself has only one annotation type element and it is named value, you can use it directly when using annotations: @annotation name (annotation value), which is equivalent to: @annotation name (value = annotation value)

@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{
	//省略实现部分
}

3.2.3 Special usage three:

If an annotation type element in an annotation is an array type, and only one value needs to be filled in when using it, then when using the annotation, it can be written directly as: @annotation name (type name = type value), which It is equivalent to the standard writing method: @ annotation name (type name = {type value})!

@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{
	//省略实现部分
}

3.2.4 Special usage four:

If the @Target of an annotation is defined as Element.PACKAGE, then this annotation is configured in package-info.java and cannot be configured directly on the package code of a certain class.

Four:  Runtime analysis of custom annotations

This chapter is the core of using annotations. After reading this chapter, you will understand how to detect annotations when the program is running and perform a series of special operations !

4.1 Review retention of annotations

First, let’s review the previously customized annotation @CherryAnnotation and configure it on the class Student. The code is as follows:

@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!");
        }
    }
}

Note the three stages of retention:

  1. Java source file stage;
  2. Compiled to class file stage;
  3. Runtime stage.

Only when the retention of annotations is in the running stage, that is, when @Retention(RetentionPolicy.RUNTIME)modified annotations are used, the annotations can be detected and a series of special operations can be performed when the JVM is running. 

4.2 Reflection operation to obtain annotations

Therefore, our goal is clear: to explore and use compile-time content (compilation-time configuration annotations) at runtime, we must use the soul technology in Java-reflection!

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();
        }
    }
}

explain:

(1) If the annotation we want to obtain is configured on the method, then we need to get it from the Method object; if it is configured on the attribute, we need to get it from the Field object corresponding to the attribute. If it is configured on the type , needs to be obtained from the Class object. In short, get it from whomever it is!
(2) The isAnnotationPresent(Class<? extends Annotation> annotationClass) method is used to specifically determine whether the element is configured with a specified annotation; (3) The
getAnnotation(Class<A> annotationClass) method is used to obtain the specified annotation on the element. Then call the annotation type element method of the annotation to obtain the value data during configuration;
(4) There is also a method getAnnotations() on the reflection object, which can obtain all the annotations configured on the object. It will return us an annotation array. It should be noted that the type of the array is an Annotation type. This Annotation is an interface from the java.lang.annotation package.

Original address:  Detailed introduction to custom annotations_cherry’s blog-CSDN blog_custom annotations

Guess you like

Origin blog.csdn.net/m0_50370837/article/details/121226378#comments_28087535