Home  >  Article  >  Java  >  Java annotation mechanism and its principles

Java annotation mechanism and its principles

伊谢尔伦
伊谢尔伦Original
2017-02-03 14:47:311287browse

Annotations are also called metadata, such as our common @Override and @Deprecated. Annotations are a feature introduced since JDK1.5. They are used to explain the code. They can be used to describe packages, classes, interfaces, fields, and method parameters. , local variables, etc. for annotation. Its main functions are as follows:

  1. Generate documents and generate javadoc documents through the metadata identified in the code.

  2. Compilation check allows the compiler to check and verify during compilation through the metadata identified in the code.

  3. Dynamic processing at compile time. Dynamic processing at compile time through the metadata identified in the code, such as dynamically generating code.

  4. Dynamic processing at runtime. Dynamic processing at runtime through the metadata identified in the code, such as using reflection injection instances.

General annotations can be divided into three categories:

  • The first category is the standard annotations that come with Java, including @Override, @Deprecated and @ SuppressWarnings are used to indicate overriding a method, indicating that a certain class or method is obsolete, and indicating warnings to be ignored. The compiler will check after being marked with these annotations.

  • The first category is meta-annotations. Meta-annotations are annotations used to define annotations, including @Retention, @Target, @Inherited, @Documented, and @Retention is used to indicate that annotations are retained. stage, @Target is used to indicate the scope of use of annotations, @Inherited is used to indicate that annotations can be inherited, and @Documented is used to indicate whether to generate javadoc documents.

  • The first category is custom annotations. You can define annotations according to your own needs, and you can annotate custom annotations with meta-annotations.

Use of annotations

The use of annotations is very simple. Just mark an annotation where an annotation is required. For example, annotate the method:

public class Test {
    @Override    
      public String tostring() {        
          return "override it";
    }
}

For example, annotate on the class:

@Deprecated
public class Test {
}

So Java’s built-in annotations can be used directly, but many times we need to define some annotations ourselves. For example, common spring uses a lot of annotations. to manage dependencies between objects. Let's take a look at how to define your own annotation. Let's implement such an annotation: inject a string into a certain class through @Test, and inject a string into a certain method through @TestMethod.

① Create a Test annotation, declare it to act on the class and retain it until runtime. The default value is default.

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {
    String value() default "default";
}

② Create a TestMethod annotation, declare it to act on the method and retain it until runtime.

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface TestMethod {
    String value();
}

③The test class outputs two strings, default and tomcat-method, after running. Because @Test does not pass in a value, the default value is output, while @TestMethod outputs the injected string.

@Test()
public class AnnotationTest {
    @TestMethod("tomcat-method")
    public void test(){
    }
    public static void main(String[] args){
        Test t = AnnotationTest.class.getAnnotation(Test.class);
        System.out.println(t.value());
        TestMethod tm = null;
        try {
            tm = AnnotationTest.class.getDeclaredMethod("test",null).getAnnotation(TestMethod.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(tm.value());
    }
}

The principle of annotations

The previous article introduced how to use Java's built-in annotations and how to customize an annotation. Next, let's take a look at the principles of annotation implementation and see what is under the larger Java system. How to support annotations. Let’s go back to the custom annotation example above. For the annotation Test, as follows, if the AnnotationTest class is annotated, the value of the annotation declaration can be obtained at runtime through AnnotationTest.class.getAnnotation(Test.class). From the above sentence, you can It can be seen that it obtains the Test annotation from the class structure, so the annotation must have been added to the class structure at some point.

@Test("test")
public class AnnotationTest {
    public void test(){
    }
}

The process from java source code to class bytecode is completed by the compiler. The compiler will parse the java source code and generate class files. Annotations are also processed by the compiler during compilation. The compiler will The annotation symbols are processed and appended to the class structure. According to the JVM specification, the class file structure is in a strictly ordered format. The only way to append information to the class structure is to save it in the attributes attribute of the class structure. We know that classes, fields, and methods have their own specific table structures in the class structure, and each has its own attributes. As for annotations, their scope of action can also be different. They can act on classes or on On a field or method, the compiler will store the annotation information in the properties of the class, field, or method.

After our AnnotationTest class is compiled, the corresponding AnnotationTest.class file will contain a RuntimeVisibleAnnotations attribute. Since this annotation is applied to the class, this attribute is added to the attribute set of the class. That is, the key-value pair value=test of the Test annotation will be recorded. When the JVM loads the AnnotationTest.class file bytecode, it will save the RuntimeVisibleAnnotations attribute value to the Class object of AnnotationTest, so the Test annotation object can be obtained through AnnotationTest.class.getAnnotation(Test.class), and then through The Test annotation object obtains the attribute values ​​​​in Test.

You may have questions here, what is the Test annotation object? In fact, the essence of the compiled annotation is an interface that inherits the Annotation interface, so @Test is actually "public interface Test extends Annotation". When we call it through AnnotationTest.class.getAnnotation(Test.class), the JDK will generate it through a dynamic proxy An object that implements the Test interface, and sets the RuntimeVisibleAnnotations attribute value into this object. This object is the Test annotation object, and the annotation value can be obtained through its value() method.

The entire process of Java annotation implementation mechanism is as shown above. Its implementation requires the cooperation of the compiler and JVM.


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn