Annotation知识积累

Annotation知识积累

1.Annotation注解的基础知识点

1.1定义:

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

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

需要注意的是java注解有4个元注解,用于作用在其他注解的注解

  • @Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
  • @Documented - 标记这些注解是否包含在用户文档中。
  • @Target - 标记这个注解应该是哪种 Java 成员。
  • @Inherited - 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)

1.2三个重要的主干类

Annotation

package java.lang.annotation;
public interface Annotation {

    boolean equals(Object obj);

    int hashCode();

    String toString();

    Class<? extends Annotation> annotationType();
}

ElementType

package java.lang.annotation;

public enum ElementType {
    TYPE,               /* 类、接口(包括注释类型)或枚举声明  */

    FIELD,              /* 字段声明(包括枚举常量)  */

    METHOD,             /* 方法声明  */

    PARAMETER,          /* 参数声明  */

    CONSTRUCTOR,        /* 构造方法声明  */

    LOCAL_VARIABLE,     /* 局部变量声明  */

    ANNOTATION_TYPE,    /* 注释类型声明  */

    PACKAGE             /* 包声明  */
}

RetentionPolicy

package java.lang.annotation;
public enum RetentionPolicy {
    SOURCE,            /* Annotation信息仅存在于编译器处理期间,编译器处理完之后就没有该Annotation信息了  */

    CLASS,             /* 编译器将Annotation存储于类对应的.class文件中。默认行为  */

    RUNTIME            /* 编译器将Annotation存储于class文件中,并且可由JVM读入 */
}

说明:

(01) Annotation 就是个接口。

"每 1 个 Annotation" 都与 "1 个 RetentionPolicy" 关联,并且与 "1~n 个 ElementType" 关联。可以通俗的理解为:每 1 个 Annotation 对象,都会有唯一的 RetentionPolicy 属性;至于 ElementType 属性,则有 1~n 个。

(02) ElementType 是 Enum 枚举类型,它用来指定 Annotation 的类型。

"每 1 个 Annotation" 都与 "1~n 个 ElementType" 关联。当 Annotation 与某个 ElementType 关联时,就意味着:Annotation有了某种用途。例如,若一个 Annotation 对象是 METHOD 类型,则该 Annotation 只能用来修饰方法。

(03) RetentionPolicy 是 Enum 枚举类型,它用来指定 Annotation 的策略。通俗点说,就是不同 RetentionPolicy 类型的 Annotation 的作用域不同。

"每 1 个 Annotation" 都与 "1 个 RetentionPolicy" 关联。

a) 若 Annotation 的类型为 SOURCE,则意味着:Annotation 仅存在于编译器处理期间,编译器处理完之后,该 Annotation 就没用了。 例如," @Override" 标志就是一个 Annotation。当它修饰一个方法的时候,就意味着该方法覆盖父类的方法;并且在编译期间会进行语法检查!编译器处理完后,"@Override" 就没有任何作用了。
b) 若 Annotation 的类型为 CLASS,则意味着:编译器将 Annotation 存储于类对应的 .class 文件中,它是 Annotation 的默认行为。
c) 若 Annotation 的类型为 RUNTIME,则意味着:编译器将 Annotation 存储于 class 文件中,并且可由JVM读入。
这时,只需要记住"每 1 个 Annotation" 都与 "1 个 RetentionPolicy" 关联,并且与 "1~n 个 ElementType" 关联。学完后面的内容之后,再回头看这些内容,会更容易理解。

2.常用的Annotation功能

(1)用于拦截器中对指定接口进行处理
例如:自定义注解+拦截器 实现登录校验
(2) 用于切面对指定方法进行处理
例如:自定义注解+AOP 实现日志输出
(3)用于实体类,可为该类,字段等添加注解,实现一些复杂功能
例如
1)Excel 数据导入导出
2)ES根据查询实体生成 query查询语向

3.写一个拥有基本功能的注解

3.1创建一个注解

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Target(value = METHOD)//此注解用于修饰方法
@Retention(value = RUNTIME)//运行时起作用
public @interface initdata {
    String msg() default "default annotation param -";//定义一个属性做演示
}

注意:两个必须设置的元注解,分别定义注解的使用对象和注解的使用范围。

3.2在自定义类中使用注解

public class Demo {
    @initdata(msg = "user set annotation param")
    public void init(String param){
        System.out.println("this is method init 1 param :"+param);

    }

    @initdata
    public void init2(String param){
        System.out.println("this is method init 2 param :"+param);

    }
}

方法1添加了属性值,而方法2中没有添加。

3.3使用反射的机制,添加对应的功能

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Main {
    public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, IllegalAccessException, NoSuchMethodException, InstantiationException {
        Class clazz = Class.forName("Demo");
        Method[] methods = clazz.getMethods();
        if(methods!=null && methods.length != 0){
            for(Method method : methods){
                boolean flag = method.isAnnotationPresent(initdata.class);
                if(flag){
                    //打印注解中的参数
                    initdata annotation = method.getAnnotation(initdata.class);
                    System.out.println((annotation.msg()));
                    //实例化对象
                    Demo demo = (Demo)clazz.getConstructor(null).newInstance(null);
                    //调用此方法
                    method.invoke(demo,"param - 在反射中调用");
                }
            }
        }
    }
}

3.4输出结果:

user set annotation param
this is method init 1 param :param - 在反射中调用
default annotation param -
this is method init 2 param :param - 在反射中调用

4.总结

注解仅仅是元数据,不包括任何业务逻辑。一个注解应该有对应的消费者,否则定义的注解是没有任何作用的。也就是需要在合适的时机来翻译注解对应的逻辑,一般可以结合反射技术来实现。比如@Override这个注解它在字节码级别工作 本身没有任何业务逻辑,JVM是它的消费者负责把相应的逻辑解析出来。

5.参考

https://www.bilibili.com/video/BV1Py4y1Y77P/?spm_id_from=333.337.search-card.all.click&vd_source=c0f7b4239efb5417bae7431353889e79

posted @ 2023-03-19 18:15  身带吴钩  阅读(13)  评论(0编辑  收藏  举报