注解有三个可见性:
源码可见(SOURCE)
字节码可见(CLASS)
运行时可见(RUNTIME)
这三个可见性是层层递增的,也就是说运行时可见的注解在前两种状态都是可见的。
下面来验证说明下
三个注解源码:
TestAnnoRetentionSource:
@Retention(RetentionPolicy.SOURCE) @Target(ElementType.FIELD) public @interface TestAnnoRetentionSource { }
TestAnnoRetentionClass:
@Retention(RetentionPolicy.CLASS) @Target(ElementType.FIELD) public @interface TestAnnoRetentionClass { }
TestAnnoRetentionRuntime:
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface TestAnnoRetentionRuntime { }
测试类如下:
public class AnnotationTest { @TestAnnoRetentionSource public int sourceVisible; @TestAnnoRetentionClass public int classVisible; @TestAnnoRetentionRuntime public int runtimeVisible; public static void main(String[] args) { Class<AnnotationTest> clazz = AnnotationTest.class; for (Field each : clazz.getFields()) { System.out.println(each.getName() + ":"); for (Annotation anno : each.getAnnotations()) { System.out.println("\t" + anno.annotationType().getName()); } System.out.println(); } } }
可以看到三个注解类分别对应三个可见性,并且测试类中三个实例变量也分别用对应的注解修饰。
测试类输入是:
sourceVisible: classVisible: runtimeVisible: cn.teaey.test.annotation.TestAnnoRetentionRuntime
到现在我们能知道,只有课件性为Runtime的注解在我们代码运行的时候能够获取到。
再用javap命令查看下测试类的字节码(class)文件
命令:javap -verbose AnnotationTest
输入(部分):
1. const #5 = Asciz sourceVisible;
2. const #7 = Asciz classVisible;
3. const #8 = Asciz RuntimeInvisibleAnnotations;
4. const #9 = Asciz Lcn/teaey/test/annotation/TestAnnoRetentionClass;;
5. const #10 = Asciz runtimeVisible;
6. const #11 = Asciz RuntimeVisibleAnnotations;
7. const #12 = Asciz Lcn/teaey/test/annotation/TestAnnoRetentionRuntime;;
第1行能看出,sourceVisible在class字节码中没有任何注解修饰
第2、3、4行可以看出,classVisible变量被一个RuntimeInvisibleAnnotations运行时不可见的注解TestAnnoRetentionClass修饰
第5、6、7行说明,runtimeVisible变量被一个RuntimeVisibleAnnotations运行时可见的注解TestAnnoRetentionRuntime修饰。
总结:
SOURCE:只存在于JAVA源码(.java)文件中
CLASS:存在于JAVA源码和字节码(.class)文件中
RUNTIME:在源码、字节码中可见,同时可以在代码中访问