1.介绍
注解 Annotation
- 就是Java代码里的特殊标记,作用是让其他程序根据注解信息来决定什么是执行该程序
 - 注解:注解可以在类上、构造器上、方法上、成员变量上、参数上等位置
 
自定义注解
/**
 * 自定义注解
 */
public @interface MyTest1 {
    String aaa();
    boolean bbb() default true;
    String[] ccc();
}
 
特殊属性名:value
- 如果注解中只有一个vlue属性,使用注解时,value名称可以不写
 
public @interface MyTest2 {
    String value(); // 特殊属性
}
 
注解的原理
- 注解本质是一个接口,Java中所有的注解都是继承了Annotation接口的
 - @注解(…): 其实就是一个实现类对象,实现了该注解以及Annotation接口

 
2.元注解
元注解
- 指的是:修饰注解的注解
 - @Target 声明被修饰的注解在哪些位置使用 
  
- 类,成员变量,成员方法,成员参数,构造器,局部变量
 
 - @Retention 声明注解的保留周期 
  
- SOURCE 只作用在源码阶段,字节码文件中不存在
 - CLASS (默认值)保留到字节码文件阶段,运行阶段不存在
 - RUNTIME (开发常用)一直保留到运行解阶段
 
 
3.注解的解析
什么是注解的解析
- 就是判断类上、方法上、成员变量上是否存在注解,并把注解里的内容给解析出来
 
如何解析注解
- 指导思想:要解析谁上面的注解,就应该先拿到谁
 - 比如要解析类上面的注解,则应该先获取该类的Class对象,在通过Class对象解析其上面的注解
 - 比如要解析成员方法上的注解,则应该获取到该成员方法的Method对象,再通过Method对象解析其上面的注解
 - Class、Method、Field、Constructor 都实现了AnnotatedElement接口,都拥有解析注解的能力

 
案例
 先定义注解MyTest4
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest4 {
    String value();
    double aaa() default 100;
    String[] bbb();
}
 
在Demo类中定义test1方法,在类和方法上使用MyTest4的注解
@MyTest4(value = "蜘蛛精", aaa = 991, bbb = {"Java", "Python"})
public class Demo {
    @MyTest4(value = "孙悟空", aaa = 22, bbb = {"HTML", "CSS"})
    public void test1() {
    }
}
 
在AnnotationTest3测试类上,解析Demo类中的全部注解
public class AnnotationTest3 {
    @Test
    public void parseClass() throws NoSuchMethodException {
        // 1.先得到Class对象
        Class demoClass = Demo.class;
        // 2.解析类上的注解
        // 判断类上是否包含了某个注解
        if (demoClass.isAnnotationPresent(MyTest4.class)) {
            MyTest4 myTest4 = (MyTest4) demoClass.getDeclaredAnnotation(MyTest4.class);
            System.out.println(myTest4.value());
            System.out.println(myTest4.aaa());
            System.out.println(Arrays.toString(myTest4.bbb()));
        }
        // 3.解析方法上的注解
        Method test1 = demoClass.getDeclaredMethod("test1");
        if (test1.isAnnotationPresent(MyTest4.class)) {
            MyTest4 myTest4 = test1.getDeclaredAnnotation(MyTest4.class);
            System.out.println(myTest4.value());
            System.out.println(myTest4.aaa());
            System.out.println(Arrays.toString(myTest4.bbb()));
        }
    }
}
 
4.注解的应用场景
案例:模拟Junit框架
 需求:定义若干个方法,只有加了MyTest注解,就会触发该方法执行
 分析:
- 定义一个自定义注解MyTest,只能注解方法,存放范围是一直都在
 - 定义若干个测试方法,部分方法加上@MyTest注解,部分方法不加
 - 模拟Junit程序,可以触发加了@MyTest注解的方法执行
 
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest {
}
public class AnnotationTest4 {
    public void test1() {
        System.out.println("==test1==");
    }
    @MyTest
    public void test2() {
        System.out.println("==test2==");
    }
    public void test3() {
        System.out.println("==test3==");
    }
    @MyTest
    public void test4() {
        System.out.println("==test4==");
    }
    
	public static void main(String[] args) throws Exception {
        // 1.获取对象
        Class annotationTest4Class = AnnotationTest4.class;
        // 2.获取所有方法
        Method[] methods = annotationTest4Class.getDeclaredMethods();
        // 3.遍历所有方法
        AnnotationTest4 annotationTest4 = new AnnotationTest4();
        for (Method method : methods) {
            // 4.判断如果存在MyTest注解
            if (method.isAnnotationPresent(MyTest.class)) {
                // 5.存在MyTest注解,执行该方法
                method.invoke(annotationTest4);
            }
        }
    }
}