一、概述
(一)注解的概述

  • Java 注解(Annotation)又称Java标注,是JDK5引入的注释机制。
  • Java 语言中的类、构造器、方法、成员变量、参数等都可以以注解的形式标注。

(二)注解的作用

  • 对Java中类、方法、变量做标记,然后进行特殊处理。

二、自定义注解
(一)自定义注解格式

public @interface 注解名称 {
	public 属性类型 属性名() default 默认值;
}

(二)自定义注解示例

public @interface MyBook {
    String id();
    String[] names();
    double price();
    //特殊的属性value,当只定义一个属性且名称为value则调用时可不写value,若有多个,则必须填写
    String value();
}

三、元注解

(一)概念: 元注解是以注解的形式作用在注解中的一种注解形式。

(二)常见元注解

  • @Target——约束自定义注解的使用范围
  • @Retention——声明注解的生命周期

(三)常见元注解参数的常用值

@Target——ElementType枚举类


作用域

TYPE

类/接口

FIELD

成员变量

METHOD

成员方法

PARAMETER

方法参数

CONSTRUCTOR

构造器

LOCAL_VARIABLE

局部变量

@Retention——RententionPolicy枚举类


作用域

SOURCE

作用于源码阶段,生成的字节码文件不存在

CLASS

作用于源码阶段,字节码文件阶段,运行阶段不存在,默认值

RUNTIME

作用于源码阶段,字节码文件阶段,运行阶段,开发常用

(四)使用元注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Book{
    String value();
}

四、注解解析

(一)概念: 注解解析是判断注解是否存在并解析其内容。

(二)相关API

  • Annotation接口:注解的原始接口
  • AnnotationElement:定义了注解解析方法

方法

说明

Annotation[] getDeclaredAnnotations()

获取当前对象上使用的所有注解,返回注解数组

T getDeclaredAnnotation(Class<T> annotationClass)

根据注解类型获得对应注解对象

boolean isAnnotationPresent(Class<Annotation> annotationClass)

判断对象是否使用了指定接口

(三)解析注解的技巧: 注解在哪个成分上,先解析哪个成分对象

(四)解析案例

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface Book{
    String value(); //书名
    double price() default 100; //价格 默认为100
    String[] authors(); //多位作者
}

@Book(value = "《Java深度学习》",price = 100,authors = {"xxx","xxx","xxx"})
class BookStore{
    private String name;
    private double price;
    private String[] authors;

    @Book(value = "《Java浅度学习》",price = 50,authors = {"佚名"})
    public void text(){

    }

    @Override
    public String toString() {
        return "BookStore{" +
                "name='" + name + '\'' +
                ", price=" + price +
                ", authors=" + Arrays.toString(authors) +
                '}';
    }
}


public class AnnotationDemo{
    @Test
    public void parseClass(){
        //1、先得到类对象
        Class c = BookStore.class;

        //2、判断是否存在
        if (c.isAnnotationPresent(Book.class)){
            //3、直接获取注解对象
            Book annotation = (Book) c.getDeclaredAnnotation(Book.class);
            System.out.println(annotation.value());
            System.out.println(annotation.price());
            System.out.println(Arrays.toString(annotation.authors()));
        }
    }

    @Test
    public void parseMethod() throws NoSuchMethodException {
        //1、先得到类对象
        Method c = BookStore.class.getMethod("text");
        //2、判断是否存在
        if (c.isAnnotationPresent(Book.class)){
            //3、直接获取注解对象
            Book annotation = (Book) c.getDeclaredAnnotation(Book.class);
            System.out.println(annotation.value());
            System.out.println(annotation.price());
            System.out.println(Arrays.toString(annotation.authors()));
        }
    }
}

/*测试结果*/
《Java深度学习》
100.0
[xxx, xxx, xxx]
======================
《Java浅度学习》
50.0
[佚名]

五、注解的应用——模拟Junit测试框架

/*
* 需求:定义若干个方法,只要加了MyTest注解,就可以触发执行
* 分析:获取类中成员方法,判断是否有注解,若有注解则执行,否则不执行
*/

public class JunitDemo {

    @MyJunit
    public static void test1(){
        System.out.println("=======test1========");
    }

    public static void test2(){
        System.out.println("=======test2========");
    }


    @MyJunit
    public static void test3(){
        System.out.println("=======test3========");
    }

    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {
        Class anno = JunitDemo.class;
        Method[] methods = anno.getMethods();

        for (Method method :methods) {
            if (method.isAnnotationPresent(MyJunit.class)){
                method.invoke(anno);
            }else System.out.println(method.getName() + "未执行");
        }
    }

}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface MyJunit{}