关于Java的Retention元注解
关于Java的Retention元注解
摆渡者 发表于9个月前
关于Java的Retention元注解
  • 发表于 9个月前
  • 阅读 158
  • 收藏 1
  • 点赞 0
  • 评论 0

【腾讯云】新注册用户域名抢购1元起>>>   

摘要: 关于Java注解中的Retention,由于开发中用的很少,所以一直没弄明白它的作用,于是特意花点时间研究了一下,并把结果记录在此。

Demo

写了一个自定义注解:

package com.my.test;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface MyAnnotation {
	String value();
}

定义了一个类A,并用MyAnnotation标注。测试类中:

package com.my.test;

@MyAnnotation("This is MyAnnotation. ^_^")
class A {}

public class Test {
	public static void main(String[] args) {
		MyAnnotation annotation = A.class.getAnnotation(MyAnnotation.class);
		if (annotation != null) {
			System.out.println(annotation.value());
		} else {
			System.out.println("No such annotation.");
		}
	}
}

执行结果:

No such annotation.

如果把MyAnnotation类的Retention改为RetentionPolicy.CLASS,结果还是No such annotation。

如果改为RetentionPolicy.RUNTIME,此时的结果为:

This is MyAnnotation. ^_^

 

描述

在JavaDoc中,RetentionPolicy是这样描述的:

RetentionPolicy 说明 举例
SOURCE 注解只保留在代码中,class文件中没有 @Override, @SupressWarnings
CLASS 注解会保留在class文件中,但运行时不能取得  
RUNTIME 注解会保留在class文件中,而且运行时可以取得 @Deprecated

可以理解的是,@Override注解只是为了编译器能检查是否当前的方法真的是在复写父类的方法,而@SuppressWarnings也只是为了抑制代码中的警告而已,在代码编译之后并没有作用,所以不需要写在CLASS文件中,于是,这类注解的RetentionPolicy自然应该为SOURCE。

 

验证

为了验证以上说明,接下来,我们使用javap工具把标注有MyAnnotation注解的类A的class文件进行反编译。

RetentionPolicy.SOURCE

RetentionPolicy.CLASS

可以看到:

  • 中间包含了RuntimeInvisibleAnnotations这一部分,表明注解确实已经写入到class文件中,而且是运行时不可见的(RuntimeInvisibleAnnotations)
  • 而在常量池中,可以清楚的看到自定义注解的权限定类名,注解的属性,和属性的值均被写入到class中,而且是常量

RetentionPolicy.RUNTIME

可以看到:

  • 和CLASS一样,中间也包含了RuntimeInvisibleAnnotations这一部分,但注解是运行时可见的(RuntimeVisibleAnnotations)
  • 和CLASS一样,注解的权限定类名,注解的属性,和属性的值同样被写入到class的常量池

到这里可以得出以下结论:

  • 一个带注解的类在编译后,如果注解的RetentionPolicy是CLASS或RUNTIME,那么此注解的信息会被记录到类的量池中
  • 如果要在代码中获取注解,需要把Retention设置为RetentionPolicy.RUNTIME

 

-------------分----------割----------线-------------

另外,通过这篇博客,也印证了前文中的观点:注解信息来自类的常量池

注解本质是一个继承了Annotation的特殊接口,其具体实现类是Java运行时生成的动态代理类。通过代理对象调用自定义注解(接口)的方法,会最终调用AnnotationInvocationHandler的invoke方法。该方法会从memberValues这个Map中索引出对应的值。而memberValues的来源是Java常量池。

 

 

参考链接:

https://stackoverflow.com/questions/3933119/how-to-view-annotation-of-java-classfile-via-command-line

http://blog.csdn.net/lylwo317/article/details/52163304

 

  • 打赏
  • 点赞
  • 收藏
  • 分享
共有 人打赏支持
粉丝 312
博文 169
码字总数 205794
×
摆渡者
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: