Detailed explanation of annotations in java

What are annotations?

 

Annotations are metadata, which are used to describe classes, interfaces, methods, properties, etc. of java code, and then the application can do some actions according to the annotations. For example, the annotation @Service in Spring indicates that this is a service class, and then the Spring framework will create an instance for it, and set the key value and save it in the ApplicationContext according to the parameters of the annotation. These behaviors are all done by the Spring framework. Just provide metadata. For details, please refer to another article "Writing Simple Implementation Annotation SpringMVC Framework" . You can see that the function of the annotation is to mark it with a mark, indicating that this is a Service class and you want to deal with it, and provide some parameters to tell you how to deal with it. Annotations work just like xml configuration files.

 

Why introduce annotations?

Before (and after) Annotation, xml was widely used to describe metadata. Somehow some application developers and architects found that xml maintenance was getting worse and worse. They want to use something that is tightly coupled to the code, rather than a loosely coupled code description like xml. If you Google "xml vs. annotations", you'll see many debates on this issue. The most interesting thing is that xml configuration is actually introduced to separate code and configuration. The two viewpoints above may confuse you, they seem to constitute a kind of cycle, but each has its pros and cons. Below we use an example to understand the difference between the two.

 

If you want to set a lot of constant post-parameters for your application, in this case, xml is a good choice because it is not linked to specific code. If you want to declare a method as a service, then it is better to use an annotation, because in this case the annotation and the method need to be tightly coupled.

 

Many frameworks currently use a combination of xml and annotation to balance the pros and cons of the two.

 

 

Use of annotations

Java now has three built-in standard annotations

@Override, indicating that the current method definition will override the method in the superclass

@Deprecated indicates deprecated code

@SuppressWarnings turns off inappropriate compiler warnings

 

Java also provides four additional annotations, which are responsible for the creation of new annotations:

@Target : Indicates where the annotation can be used. Possible ElementType parameters are:

                     CONSTRUCTOR: Declaration of the constructor

                     FIELD: field declaration (including enum instances)

                     LOCAL_VARIABLE: local variable declaration

                     METHOD: Method declaration

                     PACKAGE: package declaration

                     PARAMETER: parameter declaration

                     TYPE: class, interface (including annotation types) or enum declaration

@Retention: Indicates at what level the annotation information needs to be saved. Optional RetentionPolicy parameters include:

                     SOURCE: The annotation will be discarded by the compiler

                     CLASS: Annotations are available in class files, but are discarded by the VM

                     RUNTIME: The VM will retain the annotation during runtime, so the information of the annotation can be read through the reflection mechanism.

@Document: include annotations in Javadoc

@Inherited: Allows subclasses to inherit annotations from parent classes

 

How to define an annotation:

 

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {
  
}

 There are generally some elements in the annotation that represent some value. The elements of the annotation look like the methods of the interface , the only difference is that you can define a default value for it. Elements cannot have indeterminate values ​​when used, that is, either have a default value, or provide the value of the element when used, and cannot use null as the default value. Annotation When there is only one element and the element name is value, you can use annotation to omit "value=" and write the value directly.

 

 

Define an element below

 

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnno{
      public String description() default "no description";
}

 then use the annotation

 

 

public class UseAnno{
      @UseCase
     public void userAnnoMethod() {
         
     }

 Then process the annotation. The processing of the annotation is to obtain the annotation information through the reflection mechanism, and then perform specific processing according to the value of the annotation element.

 

 

public static void main(String[] args){
   Method method = UseAnno.class.getMethod("useAnnoMethod");
   MyAnno anno = method.getAnnotation(MyAnno.class);
   System.out.println(method.description()); //打印出“no description”
}

 

 

 

The principle of annotation

An annotation in java is a special interface inherited from the interface `java.lang.annotation.Annotation`.

 

Let's take a look at a specific example.

Define an annotation:

 

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnno {
	int count() default 1;
}

 The compiled bytecode looks like this

 

 

Classfile /D:/platform/com.cq.platform.base/com.cq.platform.base.test/target/classes/com/cq/platform/base/test/annotation/MyAnno.class
  Last modified 2017-12-21; size 456 bytes
  MD5 checksum 3731139c896044ddb4f7dfc3d7092402
  Compiled from "MyAnno.java"
public interface com.cq.platform.base.test.annotation.MyAnno extends java.lang.annotation.Annotation
  SourceFile: "MyAnno.java"
  RuntimeVisibleAnnotations:
    0: #14(#15=[e#16.#17])
    1: #18(#15=e#19.#20)
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION

Constant pool:
   #1 = Class              #2             //  com/cq/platform/base/test/annotation/MyAnno
   #2 = Utf8               com/cq/platform/base/test/annotation/MyAnno
   #3 = Class              #4             //  java/lang/Object
   #4 = Utf8               java/lang/Object
   #5 = Class              #6             //  java/lang/annotation/Annotation
   #6 = Utf8               java/lang/annotation/Annotation
   #7 = Utf8               count
   #8 = Utf8               ()I
   #9 = Utf8               AnnotationDefault
  #10 = Integer            1
  #11 = Utf8               SourceFile
  #12 = Utf8 MyAnno.java
  #13 = Utf8               RuntimeVisibleAnnotations
  #14 = Utf8               Ljava/lang/annotation/Target;
  #15 = Utf8               value
  #16 = Utf8               Ljava/lang/annotation/ElementType;
  #17 = Utf8               TYPE
  #18 = Utf8               Ljava/lang/annotation/Retention;
  #19 = Utf8               Ljava/lang/annotation/RetentionPolicy;
  #20 = Utf8               RUNTIME
{
  public abstract int count();
    flags: ACC_PUBLIC, ACC_ABSTRACT

    AnnotationDefault:
      default_value: I#10}

 As can be seen from the decompiled information, the annotation is an interface inherited from "java.lang.annotation.Annotation"

 

So how can an interface set properties? Simply put, java generates an instance of the "interface" 'MyAnno' for you through dynamic proxy (for the current entity, such as class, method, attribute domain, etc., this proxy object is a singleton), Then assign values ​​to the properties of the proxy instance, so that configuration information can be obtained by radiation when the program is running (if the annotation is set to be visible at runtime).

 

How to achieve it?

Write a class that uses this annotation

@MyAnno(count=2)
public class TestMain {
	public static void main(String[] args) {
		MyAnno anno = TestMain.class.getAnnotation(MyAnno.class);
		int b = anno.count();
	}
}

 decompile code

Classfile /D:/platform/com.cq.platform.base/com.cq.platform.base.test/target/classes/com/cq/platform/base/test/annotation/TestMain.class
  Last modified 2017-12-21; size 900 bytes
  MD5 checksum 82c13adc58b44ced5b948006f28c0f15
  Compiled from "TestMain.java"
public class com.cq.platform.base.test.annotation.TestMain
  SourceFile: "TestMain.java"
  RuntimeVisibleAnnotations:
    0: #43(#26=I#49)
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER

Constant pool:
   #1 = Class              #2             //  com/cq/platform/base/test/annotation/TestMain
   #2 = Utf8               com/cq/platform/base/test/annotation/TestMain
   #3 = Class              #4             //  java/lang/Object
   #4 = Utf8               java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8()
   #7 = Utf8               Code
   #8 = Methodref          #3.#9          //  java/lang/Object."<init>":()V
   #9 = NameAndType        #5:#6          //  "<init>":()V
  #10 = Utf8               LineNumberTable
  #11 = Utf8 LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               Lcom/cq/platform/base/test/annotation/TestMain;
  #14 = Utf8               main
  #15 = Utf8               ([Ljava/lang/String;)V
  #16 = Class              #17            //  com/cq/platform/base/test/annotation/MyAnno
  #17 = Utf8               com/cq/platform/base/test/annotation/MyAnno
  #18 = Methodref          #19.#21        //  java/lang/Class.getAnnotation:(Ljava/lang/Class;)Ljava/lang/annotation/Annotation;
  #19 = Class              #20            //  java/lang/Class
  #20 = Utf8               java/lang/Class
  #21 = NameAndType        #22:#23        //  getAnnotation:(Ljava/lang/Class;)Ljava/lang/annotation/Annotation;
  #22 = Utf8               getAnnotation
  #23 = Utf8               (Ljava/lang/Class;)Ljava/lang/annotation/Annotation;
  #24 = InterfaceMethodref #16.#25        //  com/cq/platform/base/test/annotation/MyAnno.count:()I
  #25 = NameAndType        #26:#27        //  count:()I
  #26 = Utf8               count
  #27 = Utf8               ()I
  #28 = Fieldref           #29.#31        //  java/lang/System.out:Ljava/io/PrintStream;
  #29 = Class              #30            //  java/lang/System
  #30 = Utf8               java/lang/System
  #31 = NameAndType        #32:#33        //  out:Ljava/io/PrintStream;
  #32 = Utf8               out
  #33 = Utf8               Ljava/io/PrintStream;
  #34 = Methodref          #35.#37        //  java/io/PrintStream.println:(I)V
  #35 = Class              #36            //  java/io/PrintStream
  #36 = Utf8               java/io/PrintStream
  #37 = NameAndType        #38:#39        //  println:(I)V
  #38 = Utf8               println
  #39 = Utf8 (I)V
  #40 = Utf8               args
  #41 = Utf8               [Ljava/lang/String;
  # 42 = Utf8 year
  #43 = Utf8               Lcom/cq/platform/base/test/annotation/MyAnno;
  #44 = Utf8               b
  #45 = Utf8               I
  #46 = Utf8               SourceFile
  #47 = Utf8 TestMain.java
  #48 = Utf8               RuntimeVisibleAnnotations
  #49 = Integer            2
{
  public com.cq.platform.base.test.annotation.TestMain();
    flags: ACC_PUBLIC

    Code:
      stack=1, locals=1, args_size=1
         0: aload_0       
         1: invokespecial #8                  // Method java/lang/Object."<init>":()V
         4: return        
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0       5     0  this   Lcom/cq/platform/base/test/annotation/TestMain;

  public static void main(java.lang.String[]);
    flags: ACC_PUBLIC, ACC_STATIC

    Code:
      stack=2, locals=3, args_size=1
         0: ldc           #1                  // class com/cq/platform/base/test/annotation/TestMain
         2: ldc           #16                 // class com/cq/platform/base/test/annotation/MyAnno
         4: invokevirtual #18                 // Method java/lang/Class.getAnnotation:(Ljava/lang/Class;)Ljava/lang/annotation/Annotation;
         7: checkcast     #16                 // class com/cq/platform/base/test/annotation/MyAnno
        10: astore_1      
        11: aload_1       
        12: invokeinterface #24,  1           // InterfaceMethod com/cq/platform/base/test/annotation/MyAnno.count:()I
        17: istore_2      
        18: getstatic     #28                 // Field java/lang/System.out:Ljava/io/PrintStream;
        21: iload_2       
        22: invokevirtual #34                 // Method java/io/PrintStream.println:(I)V
        25: return        
      LineNumberTable:
        line 5: 0
        line 6: 11
        line 7: 18
        line 8: 25
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0      26     0  args   [Ljava/lang/String;
              11      15     1  anno   Lcom/cq/platform/base/test/annotation/MyAnno;
              18       8     2     b   I
}

  RuntimeVisibleAnnotations: 0:#43(#26=I#49)

It can be seen that the property setting of the annotation "MyAnno" is determined at compile time.

Then you can see the proxy class ""$Proxy1.class" under the com/sun/proxy package of the project. Where 'com.sun.proxy' is the default package name of the jdk dynamic proxy generation object. You can see this proxy class Inherited from the "java.lang.reflect.Proxy" class and implemented the "interface" MyAnno.

 

Article from: http://www.importnew.com/10294.html

https://www.cnblogs.com/huajiezh/p/5263849.html

Answer by Cao Xudong in https://www.zhihu.com/question/24401191

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326494726&siteId=291194637