美文网首页Java注解
JAVA基础篇(6)-自定义注解(理论)

JAVA基础篇(6)-自定义注解(理论)

作者: 小胖学编程 | 来源:发表于2019-09-14 18:38 被阅读0次

    JAVA && Spring && SpringBoot2.x — 学习目录

    注解可以代替配置文件的功能。

    1. 元注解

    元注解的作用就是注解其他注解,一般我们使用自定义注解时,就需要用元注解来标注我们自己的注解,一共有以下四个元注解。

    1.1 @Target注解

    说明Annotation被修饰的范围,可被用于packagestype(类,接口,枚举,Annotation类型)、类型成员(方法,构造方法,成员变量,枚举值)、方法参数和本地变量(如循环变量,catch参数)。

    一句话总结:定义了注解的作用范围。
    使用方法:@Target(ElementType.TYPE)

    类型 作用域
    ElementType.CONSTRUCTOR 用于描述构造器
    ElementType.FIELD 用于描述域(类的成员)
    ElementType.LOCAL_VARIABLE 用于描述局部变量(方法内部变量)
    ElementType.METHOD 用于描述方法
    ElementType.PACKAGE 用于描述包
    ElementType.PARAMETER 用于描述参数
    ElementType.TYPE 用于描述类、接口(包括注解类型) 或enum声明

    1.2 @Retention

    [瑞ten神]定义了该注解被保留的时间长短,有些只在源码中保留,有些需要编译成的class中保留,有些需要在程序运行时候保留。

    一句话总结:定义注解的声明周期。
    使用方法:@Retention(RetentionPolicy.RUNTIME)

    类型 作用域
    RetentionPoicy.SOURCE 在源文件中有效(即源文件保留)
    RetentionPoicy.CLASS 在class文件中有效(即class保留)
    RetentionPoicy.RUNTIME 在运行时有效(即运行时保留)

    1.3 Documented

    标记注解,该元注解没有属性。表明这个注解应该被javadoc工具记录。即若使用javadoc之类的工具处理,该注解信息会被生成到文档中。

    1.4 Inherited

    [in 和 瑞 ti 得]标记注解,被他标记的类型是可继承的,比如一个class被@Inherited标记,那么一个子类继承该class后,则这个注解将被用于该class的子类。

    自定义注解无@Inherited 自定义注解有@Inherited
    子类能否继承父类上的注解
    子类方法,实现了父类的抽象方法,能否可以继承注解
    子类方法,继承了父类方法,能否继承注解
    子类方法,覆盖了父类方法,能否继承注解
    @MyAnno
    public interface Eat {
    }
    
    class Parent implements Eat {
    
    }
    
    class Child implements Eat {
    
    }
    
    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    @RequestMapping
    @interface MyAnno {
    
    
    }
    
    class Test {
    
        public static void main(String[] args) {
            MyAnno eatAnnotation = Eat.class.getAnnotation(MyAnno.class);
            MyAnno parentAnnotation = Parent.class.getAnnotation(MyAnno.class);
            MyAnno childAnnotation = Child.class.getAnnotation(MyAnno.class);
            System.out.println(eatAnnotation);  //@com.galax.common.anno.customAnno.MyAnno()
            System.out.println(parentAnnotation); //null
            System.out.println(childAnnotation); //null
        }
    }
    

    我们的注解标注了@Inherited表示该注解可以被继承,但是parentAnnotation和childAnnotation依旧是null。需要注意:@Inherited继承只能发生在类上,而不发生在接口上(也就是说标注在接口上依旧不能被继承。)

    2. 自定义注解

    1. 自定义注解的格式

    public @interface 注解名 {定义体}
    

    使用@interface定义的一个注解,自动继承了java.lang.annotation.Annotation接口,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值就是参数的类型(返回值类型只能是:基本类型、Class、String、enum类型、Annotation类型,以及上述参数的数组类型)。可以使用default来声明参数的默认值。

    2. 需要注意的点:

    1. 只能用public或默认(default)这两个访问权修饰。
    2. 如果只有一个参数成员,最好把参数名称设为"value"。
    3. 参数的返回值,只能是基本类型,String类型,Class类型,枚举类型,注解类型以及他们的数组类型。

    3. 注解的默认值

    注解元素必须有确定的值,要么是给定的默认值,要是使用的时候赋予值。需要注意的是:若需要表达一个元素不存在值,所以使用空字符串或者负数表示某个元素不存在,在定义注解时,这已经成为一个约定用法。

    3. 如何获取自定义注解信息

    Java自定义注解是通过运行时靠反射获取注解

    AnnotatedElement对象.png Class上实现AnnotatedElement接口.png

    Java的注解解析类主要是AnnotatedElement接口的实现类,我们可以通过反射获取一个类的AnnotatedElement对象后,就可以通过下面表格的几个方法,访问Annotation信息。

    方法返回值 方法 方式解释
    T getAnnotation(Class<T> annotationClass) 返回元素上存在的,指定类型的注解。如果该类型注解不存在,则返回null。
    Annotation[] getAnnotations() 返回该元素上的所有注解。
    T getDeclaredAnnotation(Class<T> annotationClass) 返回元素上存在,指定类型的注解,忽略继承注解,如果该类型注解不存在,则返回null。
    Annotation[] getDeclaredAnnotations() 返回直接存在于类上的所有注解,忽略继承注解,如果该元素上没有任何注解,那么将返回一个长度为0的数组。
    boolean isAnnotationPresent(Class<? extends Annotation>) 判断程序元素上是否包含指定类型的注解,存在则返回true,否则返回false。

    1. 自定义注解:定义

    @Documented
    @Target(ElementType.METHOD)
    @Inherited
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MethodInfo {
        String author() default "xioapang";
        String date();
        int revision() default 1;
        String comments();
    }
    

    2. 自定义注解:使用

    public class AnnotationExample {
        @MethodInfo(author = "XXX", comments = "toString method", date = "Nov 17 2019", revision = 2)
        public String toString() {
            return "Overriden toString method";
        }
    }
    

    3. 自定义注解:解析

    @Slf4j
    public class AnnotationParsing {
        public static void main(String[] args) {
            try {
                //加载某个类上的所有方法
                for (Method method : AnnotationParsing.class.getClassLoader().loadClass("com.galax.common.anno.customAnno.AnnotationExample").getMethods()) {
                    //判断方法是否存在MethodInfo.class注解
                    if (method.isAnnotationPresent(MethodInfo.class)) {
                        //获取非继承关系的所有注解
                        for (Annotation anno : method.getDeclaredAnnotations()) {
                            log.info("注解信息:{} ", anno);
                        }
                        //获取元素上该注解的详细信息
                        MethodInfo methodAnnotation = method.getAnnotation(MethodInfo.class);
                        log.info("版本号:{}", methodAnnotation.revision());
                        log.info("作者:{}", methodAnnotation.author());
                        log.info("时间:{}", methodAnnotation.date());
                        log.info("描述:{}", methodAnnotation.comments());
                    }
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
    
        }
    }
    

    文章参考

    深入理解Java自定义注解(一):入门

    深入理解Java自定义注解(二)-使用自定义注解

    Java反射获取类和对象信息全解析

    相关文章

      网友评论

        本文标题:JAVA基础篇(6)-自定义注解(理论)

        本文链接:https://www.haomeiwen.com/subject/fuydyctx.html