认识注解

  1. 什么是注解?

注解的语法是@注解名,多用来替代配置文件配置项。它是由框架解读的(使用反射)。可以把注解对比注释理解,注释是给人看的,注解是给框架看的。

  1. 注解的使用
  • 注解定义:框架的工作
  • 注解使用:我们的工作
  • 注解解读:框架的工作
  1. 定义一个注解

所有注解的父接口都是annotation的子接口

// 定义注解
public @interface MyAnno1 {

}

可以使用注解的位置:

/**
 * 注解默认可以用在
 * 类、构造方法、方法、成员变量、形参、局部变量、包(不常用)上
 */
@MyAnno1
public class Demo1 {
    @MyAnno1
    private String name;

    @MyAnno1
    public Demo1() {

    }

    @MyAnno1
    public void fun1(@MyAnno1 String param) {
        @MyAnno1
        String s = "demo";
    }
}

注解属性

  1. 注解的属性
@MyAnno1(age = 20, name = "张三")
public class Demo2 {
}
// 注解属性的书写方式
@interface MyAnno1 {
    int age();

    String name();
}
  1. 注解属性的默认值
// 可以不需要给带有默认值得属性赋值
@MyAnno1(name = "李四")
public class Demo3 {
}

@interface MyAnno1 {
    int age() default 20;

    String name();
}
  1. 注解的value属性

注解的value属性具有特殊性,特殊性表现在使用中。

// 当只有value属性时,可以省略value=
@MyAnno1(100)
// 有其他属性时,不能省略
@MyAnno2(value = 100, name = "张三")
@MyAnno3(100)
public class Demo4 {
}

@interface MyAnno1 {
    int value();
}

@interface MyAnno2 {
    int value();

    String name();
}

@interface MyAnno3 {
    int value();

    String name() default "李四";
}
  1. 属性的类型
@MyAnno1(
        a = 20, b = "hello", c = Demo5.class, d = MyEnum.A,
        e = @MyAnno2(age = 30, name = "张三", flag = true), // 当数组元素只有一个时,可以省去大括号
        f = {1, 2, 3}
)
public class Demo5 {
}

/**
 * 属性的类型可以是8大基本类型、String、Class、Enum、注解类型、以上类型的一纬数组
 * 注意包装类型不能使用
 */
@interface MyAnno1 {
    int a();

    String b();

    Class c();

    MyEnum d();

    MyAnno2 e();

    int[] f();

}

enum MyEnum {
    A, B, C
}

@interface MyAnno2 {
    int age();

    String name();

    boolean[] flag();
}

注解的目标限定和保留策略

  1. 注解的目标限定,限定的是注解可以作用的目标
@MyAnno1
public class Demo6 {
    // 在方法上使用@MyAnno1将会报错
//    @MyAnno1
    public void fun1(){

    }
}
// @Target是限定注解作用的目标,ElementType枚举表示可作用的多种类型
@Target(ElementType.TYPE)
@interface MyAnno1{
    int value() default 10;
}
  1. 注解的保留策略
  • 保留在源码中(SOURCE):编译为Class文件时就不存在了。
  • 保留在字节码文件中(CLASS):保留在class文件中,class文件加载到内存中就不存在了。
  • 保留在内存中(RUNTIME):保留在运行时环境中,只有这种保留策略可以使用反射解读注解。
@MyAnno1
public class Demo7 {
}

// 保留策略为Runtime
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnno1 {

}

反射注解

/**
 * 反射注解
 */
public class Demo8 {
    public static void main(String[] args) throws NoSuchMethodException {
        Class<A> aClass = A.class;
        // 类上的注解
        MyAnno1 annotation = aClass.getAnnotation(MyAnno1.class);
        System.out.println(annotation.age() + "," + annotation.name());
        // 获取方法上的注解
        Method fun1 = aClass.getMethod("fun1");
        MyAnno1 anno1 = fun1.getAnnotation(MyAnno1.class);
        System.out.println(anno1.name() + "," + anno1.age());
    }
}

@MyAnno1(age = 2, name = "张顺飞")
class A {
    @MyAnno1(age = 1, name = "李老八")
    public void fun1() {

    }
}

@Retention(RetentionPolicy.RUNTIME)// 必须要限定为RUNTIME才能使用反射获取
@interface MyAnno1 {
    String name();

    int age();
}
02-13 00:15