JDK四大元注解

  <div class="htmledit_views" id="content_views">

Annotation(注解)

JDK 1.5开始, Java增加了对元数据(MetaData)的支持,也就是 Annotation(注解)。 
注解其实就是代码里的特殊标记,它用于替代配置文件:传统方式通过配置文件告诉类如何运行,有了注解技术后,开发人员可以通过注解告诉类如何运行。在Java技术里注解的典型应用是:可以通过反射技术去得到类里面的注解,以决定怎么去运行类。 
注解可以标记在包、类、属性、方法,方法参数以及局部变量上,且同一个地方可以同时标记多个注解。

  
  
  1. // 抑制编译期的未指定泛型、未使用和过时警告
  2. @SuppressWarnings({ "rawtypes", "unused", "deprecation" })
  3. // 重写
  4. @Override

meta-annotation(元注解)

除了直接使用JDK 定义好的注解,我们还可以自定义注解,在JDK 1.5中提供了4个标准的用来对注解类型进行注解的注解类,我们称之为 meta-annotation(元注解),他们分别是:
  @Target
  @Retention
  @Documented
  @Inherited
我们可以使用这4个元注解来对我们自定义的注解类型进行注解,接下来,我们挨个对这4个元注解的作用进行介绍。

@Target注解

Target注解的作用是:描述注解的使用范围(即:被修饰的注解可以用在什么地方) 。
Target注解用来说明那些被它所注解的注解类可修饰的对象范围:注解可以用于修饰 packages、types(类、接口、枚举、注解类)、类成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数),在定义注解类时使用了@Target 能够更加清晰的知道它能够被用来修饰哪些对象,它的取值范围定义在ElementType 枚举中。 

  
  
  1. public enum ElementType {
  2. TYPE, // 类、接口、枚举类
  3. FIELD, // 成员变量(包括:枚举常量)
  4. METHOD, // 成员方法
  5. PARAMETER, // 方法参数
  6. CONSTRUCTOR, // 构造方法
  7. LOCAL_VARIABLE, // 局部变量
  8. ANNOTATION_TYPE, // 注解类
  9. PACKAGE, // 可用于修饰:包
  10. TYPE_PARAMETER, // 类型参数,JDK 1.8 新增
  11. TYPE_USE // 使用类型的任何地方,JDK 1.8 新增
  12. }

@Retention注解

Reteniton注解的作用是:描述注解保留的时间范围(即:被描述的注解在它所修饰的类中可以被保留到何时) 。
Reteniton注解用来限定那些被它所注解的注解类在注解到其他类上以后,可被保留到何时,一共有三种策略,定义在RetentionPolicy枚举中。

  
  
  1. public enum RetentionPolicy {
  2. SOURCE, // 源文件保留
  3. CLASS, // 编译期保留,默认值
  4. RUNTIME // 运行期保留,可通过反射去获取注解信息
  5. }
为了验证应用了这三种策略的注解类有何区别,分别使用三种策略各定义一个注解类做测试。

  
  
  1. @Retention(RetentionPolicy.SOURCE)
  2. public @interface SourcePolicy {
  3. }

  
  
  1. @Retention(RetentionPolicy.CLASS)
  2. public @interface ClassPolicy {
  3. }

  
  
  1. @Retention(RetentionPolicy.RUNTIME)
  2. public @interface RuntimePolicy {
  3. }
用定义好的三个注解类分别去注解一个方法。

  
  
  1. public class RetentionTest {
  2. @SourcePolicy
  3. public void sourcePolicy() {
  4. }
  5. @ClassPolicy
  6. public void classPolicy() {
  7. }
  8. @RuntimePolicy
  9. public void runtimePolicy() {
  10. }
  11. }

如图所示,通过执行 javap -verbose RetentionTest命令获取到的RetentionTest 的 class 字节码内容如下。
{
  public retention.RetentionTest();
    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 3: 0

public void sourcePolicy();
flags: ACC_PUBLIC
Code:
stack=0, locals=1, args_size=1
0: return
LineNumberTable:
line 7: 0

public void classPolicy();
flags: ACC_PUBLIC
Code:
stack=0, locals=1, args_size=1
0: return
LineNumberTable:
line 11: 0
RuntimeInvisibleAnnotations:
0: #11()

public void runtimePolicy();
flags: ACC_PUBLIC
Code:
stack=0, locals=1, args_size=1
0: return
LineNumberTable:
line 15: 0
RuntimeVisibleAnnotations:
0: #14()
}
从 RetentionTest 的字节码内容我们可以得出以下两点结论:
1. 编译器并没有记录下 sourcePolicy() 方法的注解信息; 
2. 编译器分别使用了 RuntimeInvisibleAnnotations 和 RuntimeVisibleAnnotations 属性去记录了classPolicy()方法 和 runtimePolicy()方法 的注解信息;

@Documented注解

Documented注解的作用是:描述在使用 javadoc 工具为类生成帮助文档时是否要保留其注解信息。
为了验证Documented注解的作用到底是什么,我们创建一个带有 @Documented 的自定义注解类。

  
  
  1. import java.lang.annotation.Documented;
  2. import java.lang.annotation.ElementType;
  3. import java.lang.annotation.Target;
  4. @Documented
  5. @Target({ElementType.TYPE,ElementType.METHOD})
  6. public @interface MyDocumentedtAnnotation {
  7. public String value() default "这是@Documented注解为文档添加的注释";
  8. }
再创建一个 MyDocumentedTest 类。

  
  
  1. @MyDocumentedtAnnotation
  2. public class MyDocumentedTest {
  3. @Override
  4. @MyDocumentedtAnnotation
  5. public String toString() {
  6. return this.toString();
  7. }
  8. }
接下来,使用以下命令为 MyDocumentedTest 类生成帮助文档。
命令执行完成之后,会在当前目录下生成一个 doc 文件夹,其内包含以下文件。
查看 index.html 帮助文档,可以发现在类和方法上都保留了 MyDocumentedtAnnotation 注解信息。
修改 MyDocumentedtAnnotation 注解类,去掉上面的 @Documented 注解。

  
  
  1. import java.lang.annotation.ElementType;
  2. import java.lang.annotation.Target;
  3. @Target({ElementType.TYPE,ElementType.METHOD})
  4. public @interface MyDocumentedtAnnotation {
  5. public String value() default "这是@Documented注解为文档添加的注释";
  6. }
重新生成帮助文档,此时类和方法上的 MyDocumentedtAnnotation 注解信息都不见了。

@Inherited注解

Inherited注解的作用是:使被它修饰的注解具有继承性(如果某个类使用了被@Inherited修饰的注解,则其子类将自动具有该注解)。
接下来我们使用代码来进行测试,首先创建一个被@Inherited修饰的注解类MyInheritedAnnotation。

  
  
  1. import java.lang.annotation.ElementType;
  2. import java.lang.annotation.Inherited;
  3. import java.lang.annotation.Retention;
  4. import java.lang.annotation.RetentionPolicy;
  5. import java.lang.annotation.Target;
  6. @Inherited
  7. @Target(ElementType.TYPE)
  8. @Retention(RetentionPolicy.RUNTIME)
  9. public @interface MyInheritedAnnotation {
  10. public String name() default "pengjunlee";
  11. }
创建一个带有 MyInheritedAnnotation 注解的父类和一个无任何注解的子类。

  
  
  1. @MyInheritedAnnotation(name= "parent")
  2. public class Parent {
  3. }

  
  
  1. public class Child extends Parent{
  2. public static void main(String[] args) {
  3. Class<Child> child=Child.class;
  4. MyInheritedAnnotation annotation = child.getAnnotation(MyInheritedAnnotation.class);
  5. System.out.println(annotation.name());
  6. }
  7. }
运行程序,打印结果如下:
parent
  
  

注解应用举例

首先自定义一个注解类。

  
  
  1. package com.pengjunlee;
  2. import java.lang.annotation.ElementType;
  3. import java.lang.annotation.Inherited;
  4. import java.lang.annotation.Retention;
  5. import java.lang.annotation.RetentionPolicy;
  6. import java.lang.annotation.Target;
  7. @Target({ ElementType.TYPE, ElementType.METHOD })
  8. @Retention(RetentionPolicy.RUNTIME)
  9. @Inherited
  10. public @interface MyAnnotation {
  11. public String name() default "pengjunlee";
  12. }
在 AnnotationTest 中使用反射获取注解信息。

  
  
  1. package com.pengjunlee;
  2. import java.lang.annotation.Annotation;
  3. import java.lang.reflect.Method;
  4. @MyAnnotation(name = "name of type")
  5. public class AnnotationTest {
  6. @MyAnnotation(name = "name of method")
  7. public String hello() {
  8. return "hello";
  9. }
  10. public static void main(String[] args) throws NoSuchMethodException, SecurityException {
  11. Class<AnnotationTest> annotationTest = AnnotationTest.class;
  12. // 获取类上的所有注解
  13. Annotation[] annotations = annotationTest.getAnnotations();
  14. for (Annotation annotation : annotations) {
  15. // 获取注解的全类名
  16. System.out.println(annotation.annotationType().getName());
  17. }
  18. // 获取 hello() 方法
  19. Method method = annotationTest.getMethod( "hello", new Class[] {});
  20. // hello() 方法上是否有 MyAnnotation 注解
  21. if (method.isAnnotationPresent(MyAnnotation.class)) {
  22. // 获得注解
  23. MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
  24. // 获取注解的内容
  25. System.out.println(annotation.name());
  26. }
  27. }
  28. }
运行程序,打印结果如下:

  
  
  1. com.pengjunlee.MyAnnotation
  2. name of method

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值