JAVA -- 注解

一、注解介绍

1. 什么是注解

  • 注解也叫元数据
  • 注解是JDK1.5版本开始引进的一个特性,用于对代码进行说明,可以对包、类、接口、字段、方法参数、局部变量等进行注解

2. 注解分类

  • JAVA自带的标准注解
    包括@Override(标明重写某个方法)、@Deprecated(标明某个类或方法过时)和@SuppressWarnings(标明要忽略的警告),使用这些注解后编译器就会进行检查

  • 元注解,元注解是用于定义注解的注解
    包括@Retention(标明注解被保留的阶段)、@Target(标明注解使用的范围)、@Inherited(标明注解可继承)、@Documented(标明是否生成javadoc文档)、@Repeatable(标明注解是否可重复)

  • 自定义注解,根据自己的需求定义

3.注解作用

(1)生成文档,通过代码里标识的元数据生成javadoc文档
(2)编译检查,通过代码里标识的元数据,让编译器在编译期间进行检查验证
(3)编译时动态处理,编译时通过代码里标识的元数据进行动态处理,例如动态生成代码
(4)运行时动态处理,运行时通过代码里标识的元数据进行动态处理,例如使用反射注入实例

4. 注解是给谁用的

  • APT
    当开发者使用了注解修饰了类、方法、Field等成员之后,这些注解并不会自己生效,必须由开发者提供的相应代码来提取并且处理注解中的信息(动态代码生成)。这些处理和提取注解的代码统称为APT(Annotation Processing Tool)
  • 编译器
    编译器在编译期间检查验证

二、元注解解析

1. @Retention

保留期,解释说明了这个注解的存活时间,取值如下:

  • RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视
  • RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中
  • RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们

2. @Target

目标,指定了注解运用的地方

  • ElementType.ANNOTATION_TYPE 可以给一个注解进行注解
  • ElementType.CONSTRUCTOR 可以给构造方法进行注解
  • ElementType.FIELD 可以给属性进行注解
  • ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
  • ElementType.METHOD 可以给方法进行注解
  • ElementType.PACKAGE 可以给一个包进行注解
  • ElementType.PARAMETER 可以给一个方法内的参数进行注解
  • ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举

3. @Inherited

继承,如果一个类被@Inherited注释,那么他的子类(如果没有被任何注解应用)会继承父类的注解

// 首先定义一个可被继承的注解
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface Test {
}

// 父类:使用上述注解进行注释
@Test
public class A {}

// 子类:继承了父类的注解
public class B extends A {}

4. @Repeatable

可重复,JDK1.8之后加入;如果一个注解的值可同时取多个,那么这个注解将是可重复的;@Repeatable后面括号中的类相当于一个容器注解!

// Persons容器:存放Person的多个值
@interface Persons {
    Person[]  value();
}

// Person注解定义
@Repeatable(Persons.class)
@interface Person{
    String role default "";
}

// 一个注解的值可以同时取多个
@Person(role="artist")
@Person(role="coder")
@Person(role="PM")
public class SuperMan{
}

注意:注解容器解释

  • 注解容器中必须有一个value属性
  • value属性的类型是一个被@Repeatable注解过的数组

三、反射提取注解

程序在运行期间可以通过反射获取注解对象,已经通过反射获取了某个类的被注解对象后(Annotationed Element),就可以调用以下方法访问注解信息

1.具体方法

  • T getAnnotation(Class annotationClass):
    返回改程序元素上存在的、指定类型的注解,如果该类型注解不存在,则返回null。
  • Annotation[] getAnnotations():
    返回该程序元素上存在的所有注解。
  • boolean is AnnotationPresent(Class<?extends Annotation> annotationClass):
    判断该程序元素上是否包含指定类型的注解,存在则返回true,否则返回false。
  • Annotation[] getDeclaredAnnotations()
    返回直接存在于此元素上的所有注释。与此接口中的其他方法不同,该方法将忽略继承的注释。(如果没有注释直接存在于此元素上,则返回长度为零的一个数组。)该方法的调用者可以随意修改返回的数组;这不会对其他调用者返回的数组产生任何影响

2. 样例代码:

  • 首先自定义4个作用域不同的注解
/*
    作用域:类、接口、枚举类上
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation_Type {
    String value() default "类上注解";
}
/*
    作用域:方法上
 */

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation_Method {
    String value() default "方法上注解";
}
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation_Parameter {
    String value() default "参数上注解";
}

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation_Field {
    String value() default "字段上注解";
}
  • 进行测试,通过反射获取注解中的值
@MyAnnotation_Type
public class Annotation_Test {

    @MyAnnotation_Field()
    String field = "一个字段";

    @MyAnnotation_Method
    public void test(@MyAnnotation_Parameter String args) {
        System.out.println("参数值 = " + args);
    }

    // 根据反射获取类中的注解
    public static void main(String[] args) {
        // 1. 获取类上的注解
        MyAnnotation_Type t1 = Annotation_Test.class.getAnnotation(MyAnnotation_Type.class);
        System.out.println("类上注解值 --> " + t1.value());

        // 2. 获取方法上的注解
        try {
            Method method = Annotation_Test.class.getDeclaredMethod("test", String.class); // 首先获取方法
            MyAnnotation_Method t2 = method.getAnnotation(MyAnnotation_Method.class);   // 获取注解
            System.out.println("方法上的注解 --> " + t2.value());

            // 3. 获取方法上的所有注解
            Annotation[][] annotations = method.getParameterAnnotations();
            for (Annotation[] tt : annotations) {
                for (Annotation t3 : tt) {
                    if (t3 instanceof MyAnnotation_Parameter) {
                        System.out.println("参数上的注解 --> " + ((MyAnnotation_Parameter) t3).value());
                    }
                }
            }
            method.invoke(new Annotation_Test(), "改变默认参数");

            // 获取Annotation_Test类上字段field的注解
            MyAnnotation_Field t4 = Annotation_Test.class.getDeclaredField("field").getAnnotation(MyAnnotation_Field.class);
            System.out.println("字段上注解 --> " + t4.value());

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}
  • 输出结果
类上注解值 --> 类上注解
方法上的注解 --> 方法上注解
参数上的注解 --> 参数上注解
参数值 = 改变默认参数
字段上注解 --> 字段上注解
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值