深入理解Java Annotation

引言

本文将从class文件的角度来探索Annotation的相关知识,为理解JVM是如何处理Annotation打下基础.

class文件中的Annotation

假设有一个Annotation:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
@interface MyAnnotation {

    String   value() default "";

    String   name();
    int      age();
    String[] newNames();

}

对应的class文件如下:

Classfile /Users/jiangbenpeng/Documents/demos/java_note/src/annotation/MyAnnotation.class
  Last modified Mar 3, 2016; size 526 bytes
  MD5 checksum ca7b0b12bf7731c08117396e73974694
  Compiled from "MyAnnotation.java"
interface annotation.MyAnnotation extends java.lang.annotation.Annotation
  minor version: 0
  major version: 52
  flags: ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
Constant pool:
   #1 = Class              #22            // annotation/MyAnnotation
   #2 = Class              #23            // java/lang/Object
   #3 = Class              #24            // java/lang/annotation/Annotation
   #4 = Utf8               value
   #5 = Utf8               ()Ljava/lang/String;
   #6 = Utf8               AnnotationDefault
   #7 = Utf8
   #8 = Utf8               name
   #9 = Utf8               age
  #10 = Utf8               ()I
  #11 = Utf8               newNames
  #12 = Utf8               ()[Ljava/lang/String;
  #13 = Utf8               SourceFile
  #14 = Utf8               MyAnnotation.java
  #15 = Utf8               RuntimeVisibleAnnotations
  #16 = Utf8               Ljava/lang/annotation/Target;
  #17 = Utf8               Ljava/lang/annotation/ElementType;
  #18 = Utf8               TYPE
  #19 = Utf8               Ljava/lang/annotation/Retention;
  #20 = Utf8               Ljava/lang/annotation/RetentionPolicy;
  #21 = Utf8               SOURCE
  #22 = Utf8               annotation/MyAnnotation
  #23 = Utf8               java/lang/Object
  #24 = Utf8               java/lang/annotation/Annotation
{
  public abstract java.lang.String value();
    descriptor: ()Ljava/lang/String;
    flags: ACC_PUBLIC, ACC_ABSTRACT
    AnnotationDefault:
      default_value: s#7
  public abstract java.lang.String name();
    descriptor: ()Ljava/lang/String;
    flags: ACC_PUBLIC, ACC_ABSTRACT

  public abstract int age();
    descriptor: ()I
    flags: ACC_PUBLIC, ACC_ABSTRACT

  public abstract java.lang.String[] newNames();
    descriptor: ()[Ljava/lang/String;
    flags: ACC_PUBLIC, ACC_ABSTRACT
}
SourceFile: "MyAnnotation.java"
RuntimeVisibleAnnotations:
  0: #16(#4=[e#17.#18])
  1: #19(#4=e#20.#21)

可以看出,javacAnnotation文件的三个地方进行处理

1.为自定义Annotation加上extends

@interface MyAnnotation

变成了一个接口

interface annotation.MyAnnotation extends java.lang.annotation.Annotation
2.为方法添加访问权限

String name();

变成了一个抽象方法

public abstract java.lang.String name();
descriptor: ()Ljava/lang/String;
flags: ACC_PUBLIC, ACC_ABSTRACT
4.添加元Annotation信息

元Annotation指的是修饰AnnotationAnnotation,如java预定义的Annotation,本例中的元Annotation@Retention,@Target.class文件中的Annotation信息表示如下:

...
  #15 = Utf8               RuntimeVisibleAnnotations
  #16 = Utf8               Ljava/lang/annotation/Target;
  #17 = Utf8               Ljava/lang/annotation/ElementType;
  #18 = Utf8               TYPE
  #19 = Utf8               Ljava/lang/annotation/Retention;
  #20 = Utf8               Ljava/lang/annotation/RetentionPolicy;
...

RuntimeVisibleAnnotations:
  0: #16(#4=[e#17.#18])
  1: #19(#4=e#20.#21)

Java类中的Annotation

用上述自定义的Annotation来修饰类MyClass:

@MyAnnotation(
        name = "James",
        value = "KKK",
        age = 30,
        newNames = {"Big", "Jiang"}
)
public class MyClass {
}

对于的class文件如下:

  Last modified Mar 3, 2016; size 199 bytes
  MD5 checksum 62f6c0f84d550708d1686eb8be138499
  Compiled from "MyClass.java"
public class annotation.MyClass
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #3.#10         // java/lang/Object."<init>":()V
   #2 = Class              #11            // annotation/MyClass
   #3 = Class              #12            // java/lang/Object
   #4 = Utf8               <init>
   #5 = Utf8               ()V
   #6 = Utf8               Code
   #7 = Utf8               LineNumberTable
   #8 = Utf8               SourceFile
   #9 = Utf8               MyClass.java
  #10 = NameAndType        #4:#5          // "<init>":()V
  #11 = Utf8               annotation/MyClass
  #12 = Utf8               java/lang/Object
{
  public annotation.MyClass();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 15: 0
}
SourceFile: "MyClass.java"

此时的class文件中并没有找到Annotation的相关信息,原因是MyAnnotation@Retention修饰:

@Retention(RetentionPolicy.SOURCE)
@interface MyAnnotation 

RetentionPolicy.SOURCE 用来标注该Annotation仅存在源码中,将其换成 RetentionPolicy.CLASSRetentionPolicy.RUNTIME便可在class文件中看到对应对Annotation信息:

Classfile /Users/jiangbenpeng/Documents/demos/java_note/src/annotation/MyClass.class
  Last modified Mar 3, 2016; size 360 bytes
  MD5 checksum fd1ad4d03a8460f347a4cf2703bd2c8f
  Compiled from "MyClass.java"
public class annotation.MyClass
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #3.#21         // java/lang/Object."<init>":()V
   #2 = Class              #22            // annotation/MyClass
   #3 = Class              #23            // java/lang/Object
   #4 = Utf8               <init>
   #5 = Utf8               ()V
   #6 = Utf8               Code
   #7 = Utf8               LineNumberTable
   #8 = Utf8               SourceFile
   #9 = Utf8               MyClass.java
  #10 = Utf8               RuntimeInvisibleAnnotations
  #11 = Utf8               Lannotation/MyAnnotation;
  #12 = Utf8               name
  #13 = Utf8               James
  #14 = Utf8               value
  #15 = Utf8               KKK
  #16 = Utf8               age
  #17 = Integer            30
  #18 = Utf8               newNames
  #19 = Utf8               Big
  #20 = Utf8               Jiang
  #21 = NameAndType        #4:#5          // "<init>":()V
  #22 = Utf8               annotation/MyClass
  #23 = Utf8               java/lang/Object
{
  public annotation.MyClass();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 15: 0
}
SourceFile: "MyClass.java"
RuntimeInvisibleAnnotations:
  0: #11(#12=s#13,#14=s#15,#16=I#17,#18=[s#19,s#20])

源码下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值