注解随笔

⚫ 注解的定义以及使用

/*
    自定义注解的格式:
        public @interface 注解名 {

        }
 */
public class Demo02Anno {
    @Student(name = "王叔叔", age = 18, hobbies = "洗脚")
    public void method() {

    }
}

/*
    在注解中,可以定义一些属性

    属性格式:
        数据类型 属性名();
        数据类型 属性名() default 默认值;

    注解中的属性的数据类型只能是下面这几种
        1. 八种基本数据类型(byte short int long float double boolean char)
        2. Class, String, 枚举, 注解
        3. 以上所有类型的一维数组。

    注解可以加在类上面, 方法上, 成员变量上, 方法参数上....
    使用格式为@注解名

    给注解属性赋值的格式
        @注解名(属性名=属性值, 属性名=属性值)

    注意:
        1. 如果注解中的属性没有默认值,那么在使用的时候必须要进行赋值
        2. 如果注解中的属性有默认值,那么在使用的时候可以赋值也可以不赋值, 如果不赋值该属性的值就是默认值。
        3. 如果注解中的属性是一个数组, 那么在赋值的使用可以使用大括号包裹多个内容。
        4. 如果注解中的属性是一个数组, 在赋值的时候只需要赋值一个元素,那么可以省略大括号。
 */
public @interface Student {
    //姓名
    String name();

    //年龄属性,默认值为0
    int age() default 0;

    //爱好属性
    String[] hobbies();
}

16. 注解中的特殊属性value

/*
    特殊属性value

    如果一个注解中只有一个没有默认值的属性(可以有多个属性,但是没有默认值必须是1个), 并且这个属性叫做value,那么在给该属性赋值的使用,可以省略属性名。否则必须写全。
 */
public @interface Book {
    String value();
    int price() default 10;
}

@Book("西游记")
public class Demo03Anno {
    @Book("红楼梦")
    int num;

    @Book("三国演义")
    public void method() {

    }
}

17. Target元注解的使用

/*
    元注解:
        1. 元注解也是注解。
        2. 元注解是用来修饰注解的注解。
        3. 元注解要加在注解上面, 可以对某些注解进行一些限制。

    常见的元注解:
        1.@Target
        2.@Retention
 */
@MyAnno
public class Demo01Anno {
    @MyAnno
    public void method() {

    }
}
/*
    @Target是一个元注解,用来修饰注解。

    @Target用来限制注解的使用位置, 如果不使用@Target进行限制,那么注解可以在任何位置使用。

    Target中有一个属性叫做value, 这个属性用来表示被修饰的注解可以使用在哪些位置。
    value是ElementType数组类型, 里面可以传递多个数据。

    ElementType是一个枚举,枚举就是一个特殊的类, 枚举中的每一个属性都是本身类型, 枚举中的属性可以通过枚举名直接调用。
    ElementType中的每一个属性都有特别的含义:
        ElementType.TYPE: 用在类,接口上
        ElementType.FIELD:用在成员变量上
        ElementType.METHOD: 用在方法上
        ElementType.PARAMETER:用在参数上
        ElementType.CONSTRUCTOR:用在构造方法上
        ElementType.LOCAL_VARIABLE:用在局部变量上

    我们要向Target的value属性位置传递ElementType中的属性,不同的属性有不同的含义。

 */
//@Target(ElementType.TYPE)//被修饰的注解只能使用在类的上面。
//@Target(ElementType.METHOD) //被修饰的注解只能用在方法上
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface MyAnno {
}

18. Retention元注解的使用

@MyAnno1
@MyAnno2
@MyAnno3
public class Demo02Anno {
}

/*
    @Retention 元注解, 用来修饰注解。
    @Retention用来限制注解的生命周期, 如果使用@Retention修饰, 注解默认只在源代码阶段以及.class文件中有效,运行时期内存中是没有的。

    Retention只有一个属性叫做value, 这个属性是RetentionPolicy类型。 该属性表示的是被修饰的注解的生命周期。

    RetentionPolicy是一个枚举类型, 里面的每一个属性都有特别的含义。 我们要向Retention的value属性位置传递RetentionPolicy的属性。

    RetentionPolicy每个属性的含义:
       RetentionPolicy.SOURCE: 被修饰的注解只在源代码阶段有效, 一旦编译,到了.class中就会消失。
       RetentionPolicy.CLASS: 被修饰的注解只在源代码以及编译后的.class中有效
       RetentionPolicy.RUNTIME: 被修饰的注解在源代码阶段,编译后的.class中,运行时内存中有效。
 */
@Retention(RetentionPolicy.SOURCE)//表示被修饰的注解只在源代码阶段有效
public @interface MyAnno1 {
}


@Retention(RetentionPolicy.CLASS)//被修饰的注解在源代码以及class中有效
public @interface MyAnno2 {
}
@Retention(RetentionPolicy.RUNTIME)//被修饰的注解在源代码,class,运行时内存中都有效。
public @interface MyAnno3 {
}

19. 注解的解析

/*
    注解的解析: 注解解析就是获取注解中的内容(比如属性),并进行处理。

    解析相关的API:
        Annotation:接口, 所有注解都默认实现了这个接口。
        AnnotatedElement: 接口, 里面定义了很多方法可以操作注解
            Annotation[] getAnnotations():获取所有的注解
            T getAnnotation(Class annotationClass):获取指定的注解, 方法参数传递的是哪个注解的Class,那么获取的就是哪个注解。
            boolean isAnnotationPresent(Class annotationClass): 判断指定注解是否存在。 参数为注解的Class。

        解析注解需要结合反射技术去使用, 我们之前学习的Class,Method,Constructor,File反射有关的都实现了AnnotatedElement接口

        如果要操作类上面的注解,那么我们就使用Class调用AnnotatedElement中的方法操作注解就可以了
        如果要操作方法上面的注解,那么我们就使用Method调用AnnotatedElement中的方法操作注解就可以了
        如果要操作成员变量上面的注解,那么我们就使用Field调用AnnotatedElement中的方法操作注解就可以了

 */
//获取BookStore这个类上面的Book注解中的属性,并进行输出。
public class Demo01AnnoParse {
    public static void main(String[] args) throws ClassNotFoundException {
        //因为要获取BookStore类上面的注解,所以要先获取BookStore的Class对象
        Class clazz = Class.forName("cn.itcast.demo05_anno_parse.BookStore");
        //调用isAnnotationPresent判断这个类上面有么有注解。
        boolean flag = clazz.isAnnotationPresent(Book.class);//判断有没有Book注解
        //判断,如果有注解,那么就获取该注解
        if(flag) {
            //获取BookStore这个类上面Book注解
            Annotation a = clazz.getAnnotation(Book.class);
            //向下转型
            Book book = (Book)a;
            //获取book中的属性并输出
            System.out.println(book.value());
            System.out.println(book.price());
            System.out.println(book.author());
        }
    }
}
@Book(value = "Java从入门到精通", author = "佚名")
public class BookStore {

}

@Retention(RetentionPolicy.RUNTIME) //修改该注解的生命周期,让这个注解在运行时期内存中也有效。
public @interface Book {
    //value表示书名
    String value();
    //price表示价格
    int price() default 100;
    //author 作者
    String author();
}

20. 模拟单元测试

/*
    练习: 定义@MyTest注解, 模拟单元测试。

    定义@MyTest注解,在多个方法上面加上这个@MyTest注解,然后运行带有@MyTest注解的方法。

    步骤:
        获取MyTestDemo的所有的方法,遍历这些方法,判断遍历到的方法上有没有@Test注解,如果有,就让该方法执行。
 */
public class Demo01Test {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException {
        //获取MyTestDemo的Class对象
        Class clazz = Class.forName("cn.itcast.demo06_anno_test.MyTestDemo");
        //创建对象,以后调用方法使用。
        Object obj = clazz.newInstance();
        //clazz调用getMethods,获取到所有的方法(public权限)
        Method[] methods = clazz.getMethods();
        //遍历这些方法
        for (Method method : methods) {
            //判断遍历到的方法上有没有MyTest注解
            if(method.isAnnotationPresent(MyTest.class)) {
                //如果方法上有这个注解,那么就让这个方法执行。
                method.invoke(obj);
            }
        }
    }
}

@Retention(RetentionPolicy.RUNTIME) //使用元注解修饰, 让该注解在运行时期内存中也有效。
@Target(ElementType.METHOD)//限制该注解只能用在方法上。
public @interface MyTest {
}

public class MyTestDemo {
    public void methodA() {
        System.out.println("methodA....");
    }

    @MyTest
    public void methodB() {
        System.out.println("methodB....");
    }

    public void methodC() {
        System.out.println("methodC....");
    }

    @MyTest
    public void methodD() {
        System.out.println("methodD....");
    }

    public void methodE() {
        System.out.println("methodE....");
    }
}

posted on 2021-03-09 10:22  凹凹凸凸  阅读(118)  评论(0编辑  收藏  举报

导航