引言
本文将从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)
可以看出,javac对Annotation文件的三个地方进行处理
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指的是修饰Annotation的Annotation,如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.CLASS或RetentionPolicy.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])