Java注解开发

目录

基本概念

作用分类

JDK基本注解

元注解

@Retention

@Target

@Document

@Inherited

自定义注解

提取注解信息


基本概念

注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

作用分类

  • 编写文档:通过代码里标识的注解生成文档【生成文档doc文档】
  • 代码分析:通过代码里标识的注解对代码进行分析【使用反射】
  • 编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【Override】

JDK基本注解

JDK中提供了5个基本注解用法

  • @Override    :检测被该注解标注的方法是否是继承自父类(接口)的
  • @Deprecated:该注解标注的内容,表示已过时
  • @SuppressWarnings:压制警告,一般传递参数all  @SuppressWarnings("all")
  • @SafeVarargs: 处理可变长参数中的泛型,此注解告诉编译器:在可变长参数中的泛型是类型安全的
  • @FunctionalInterface:  指定的接口是函数式接口

其中@SafeVarargs是Java7中新增的,@FunctionalInterface是Java8中新增的。

元注解

JDK除了在java.lang下提供了5个基本注解之外,还在java.lang.annotation包下提供了6个Meta注解(元注解),其中有5个元注解都是用于修饰其他的注解的定义,其中@Repeatable专门用于定义Java8新增的重复注解。这里重点介绍4个常用的元注解。

@Retention

Retention只能用于修饰注释定义,用于指定被修饰的注解可以保留多长时间,@Retention包含一个RetentionPolicy类型的value成员变量,使用@Retention时必须为该value成员指定值,value成员变量的值只能是如下三个。

  • RetentionPolicy.SOURCE: 编译器把注解记录在class文件中,当运行Java程序时,JVM不可获取注解信息,这是默认值。
  • RetentionPolicy.CLASS:编译器把注解记录在class文件中,当运行Java程序时,JVM也可获取注解信息,程序可以通过反射获取该注解信息
  • RetentionPolicy.RUNTIME:注解值保留再源代码中,编译器直接丢弃这种注解

demo:

@Retention(value = RetentionPolicy.RUNTIME)
public @interface Testable {

    String value();

    int[] age() default {1,2};

}

当注解中属性值为value时,无需使用name=value的方式,可直接赋值

@Retention(RetentionPolicy.RUNTIME)

public @interface Testable {

    String value();

    int[] age() default {1,2};

}

@Target

@Target也只能修饰注解定义,它用于指定被修饰的注解能用于修饰哪些程序单元,@Target元注解也包含一个名为value的成员变量,该成员变量的值只能是如下几个

  • @Target(ElementType.TYPE)——修饰接口、类、枚举、注解
  • @Target(ElementType.FIELD)——修饰字段、枚举的常量
  • @Target(ElementType.METHOD)——修饰方法
  • @Target(ElementType.PARAMETER)——修饰方法参数
  • @Target(ElementType.CONSTRUCTOR) ——修饰构造函数
  • @Target(ElementType.LOCAL_VARIABLE)——修饰局部变量
  • @Target(ElementType.ANNOTATION_TYPE)——修饰注解
  • @Target(ElementType.PACKAGE)——修饰包

@Document

@Document用于指定被该元注解修饰的注解类将被javadoc工具提取成文档,如果定义注解类时使用了@Document修饰,则所有使用该注解修饰的程序元素的API文档中将会包含该注解。

@Inherited

@Inherited元注解指定被它修饰的注解将具有继承性,---如果某个类使用了@Xxx(定了该注解是使用了@inherited修饰)修饰,则其子类将自动被@Xxx修饰

demo

// 注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Testable {

    String value();

    int[] age() default {1,2};

}
//父类
@Testable(value = "1")
public class Test {

    public static void main(String[] args) {

        Class<Test> testClass = Test.class;
        boolean annotationPresent = testClass.isAnnotationPresent(Testable.class);
        System.out.println(annotationPresent);
    }
}
输出:
true

//子类
public class SubTest extends Test {

    public static void main(String[] args) {
        Class<SubTest> subTestClass = SubTest.class;
        boolean annotationPresent = subTestClass.isAnnotationPresent(Testable.class);
        System.out.println(annotationPresent);
    }

}
输出:
false

当给@Testable加上@Inherited时,可以看到SubTest继承了Test的注解

 

自定义注解

自定义注解使用@interface关键字,与定义一个接口非常像

public @interface Test{
  
}

内部属性值要求:

  •  基本数据类型
  •   String
  •  枚举
  •   注解
  •  以上类型的数组

定义了该注解后,就可以在程序中的任何地方使用该注解。

提取注解信息

// 定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Inherited
public @interface Testable {

    String value();

    int[] age() default {1,2};

}
@Testable(value = "Test")
public class Test {

    @Testable("run1")
    public void run1() {

    }

    @Testable("run2")
    public void run2() {

    }

    public void run3() {

    }


    public static void main(String[] args) throws ClassNotFoundException {

        Class<Test> testClass = Test.class;
        // 判断该类是否存在Testable注解
        boolean annotationPresent = testClass.isAnnotationPresent(Testable.class);
        System.out.println("testClass is AnnotationPresent===>" + annotationPresent);

        Method[] methods = testClass.getMethods();
        for (Method method : methods) {
            // 判断当前方法是否包含Testable注解
            if (method.isAnnotationPresent(Testable.class)) {
                //提取当前方法上的注解
                Testable annotation = method.getAnnotation(Testable.class);
                System.out.println(method.getName() + "===age==>" + annotation.age());
                System.out.println(method.getName() + "===value==>" + annotation.value());
            }
        }
    }
}

输出

注意:

1. 如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值。
2. 如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义值即可。
3. 数组赋值时,值使用{}包裹。如果数组中只有一个值,则{}可以省略

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值