Java和Spring注解(二)——深入理解注解

注重版权,若要转载烦请附上作者和链接

作者:Joshua_yi

链接:https://blog.csdn.net/weixin_44984664/article/details/122088060


一、注解

注解Annotation,也叫元数据

(一)注解的作用

我们可以从注解作用的对象上分析注解的作用

public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,

    /** Field declaration (includes enum constants) */
    FIELD,

    /** Method declaration */
    METHOD,

    /** Formal parameter declaration */
    PARAMETER,

    /** Constructor declaration */
    CONSTRUCTOR,

    /** Local variable declaration */
    LOCAL_VARIABLE,

    /** Annotation type declaration */
    ANNOTATION_TYPE,

    /** Package declaration */
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}
  • TYPE:注解可以作用在类、接口(包括其他注解),枚举类型上
  • ANNOTATION_TYPE:其他注解上
  • FIELD:可以作用在类的属性上
  • METHOD:方法上(不包括构造方法)
  • CONSTRUCTOR:构造方法上
  • PARAMETER:方法参数上
  • LOCAL_VARIABLE:局部变量上
  • PACKAGE:作用在包上,具体用法可以参考https://blog.csdn.net/weixin_38321868/article/details/118942209
  • TYPE_PARAMETER :表示该注解能写在类型参数的声明语句中。(eg:泛型声明)
  • TYPE_USE:表示注解可以任何用到类型的地方使用,无处不在的注解,可以让编译器执行更严格的代码检查,从而提高程序的健壮性。比如可以应用在以下地方
    • 创建对象(用 new 关键字创建)
    • 类型转换
    • 使用 implements 实现接口
    • 使用 throws 声明抛出异常
public class Solution {
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE_PARAMETER)
    public @interface isParam {
    }

    public <@isParam T> void fun1(T ob) {
        System.out.println(ob);
    }

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE_USE)
    public @interface isNotNull {
    }

    public <@isNotNull T> void fun2(@isNotNull T ob) throws @isNotNull Exception {
        String s = (@isNotNull String) "11111";
        System.out.println(ob);
    }
}

注解可以对这些程序元素添加一些额外的信息,这些信息可以用于之后的一些操作。
根据一个注解是否包含成员函数,可以将注解大致分为两类
标记注解:没有成员变量的Annotation被称为标记。这种Annotation仅用自身的存在与否来为我们提供信息,例如@override等。
元数据注解:包含成员变量的Annotation。因为它们可以接受更多的元数据,因此被称为元数据Annotation。 成员以无参数的方法的形式被声明,其方法名和返回值定义了该成员变量的名字和类型。

PS:注解没有成员变量,只有方法Annotation的成员变量在Annotation定义中以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。
可以使用default关键字为成员变量指定默认值

(二)源码解读

注解相关源码在java.lang.annotation包下
在这里插入图片描述

  • Annotation 是所有注解继承的接口,这也就是为什么说,接口底层是一个接口。
    (定义了@interface, 所有的Annotation会自动继承java.lang.Annotation这一接口,并且不能再去继承别的类或是接口)
  • AnnotationFormatError继承自Error,当注释解析器从类文件读取注释并确定该注解有错误时抛出
  • AnnotationTypeMismatchException继承自RuntimeException,表示程序试图访问注释的某个元素,该注释的类型在编译(或序列化)后发生了更改,这时候抛出该异常
  • IncompleteAnnotationException继承自RuntimeException,表示程序试图访问注释类型的元素,该元素是在注释被编译(或序列化)后添加到注释类型定义中的,也就是找不到该注解中的一些成员变量。
  • ElementType 指定注解在Java程序中注释可能出现的语法位置。
  • RetentionPolicy 描述了保留注解的策略,源码级、字节码、运行时
  • @Native 修饰类属性,表示这个变量可以被本地代码引用,常常被代码生成工具使用。
  • 其他五个注解都可以修饰其他注解,被称为元注解。(Meta-Annotation)

PS:看了各种官方文档,还没有找到对这个Meta-Annotation的准确定义。
只知道可以作用在其他注解上的注解叫做元注解。为了区别于自己定义的元注解,以下统称为基本元注解

二、基本元注解与注解解析

在说明该五个基本元注解之前,需要对ElementType(前文已经有相关阐述)和RetentionPolicy进行讲解

(一)ElementType

见前文

(二)RetentionPolicy

public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     */
    SOURCE,

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     */
    CLASS,

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     *
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}

  • RetentionPolicy.SOURCE:表明注解会被编译器丢弃,字节码中不会带有注解信息。一般用于需要在编译器层面就可以发现的问题。比如@override就是代码级别可见,与编译器相结合来检查问题。

  • RetentionPolicy.CLASS:表明注解会被写入字节码文件,是@Retention的默认值。简单来说,其自定义注解解析需要实现AbstractProcessor的process()方法。基本使用可以参考该文章 java注解之编译时注解RetentionPolicy.CLASS 基本用法

  • RetentionPolicy.RUNTIME:表明注解会被写入字节码文件,并且能够被JVM 在运行时获取通过反射的方式解析到。

反射常用到的函数如下

  • T getAnnotation(Class) : 获得当前对象的指定的注解。
  • Annotation[] getAnnotations() X: 获得当前对象的所有注解
  • boolean isAnnotationPresent(annotationClass): 当前对象是否有注解。

PS:定义了一个注解之后,只是一个空的定义,需要通过定义注解解析来赋予其实在的意义。常用的自定义的注解解析,是通过反射来进行相关操作的,也就是说需要指定注解的Retention到RUNTIME。

(三)@Documented

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}

在用javadoc命令生成API文档后,文档里会出现该注解说明

(四)@Inherited

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}

@Inherited 表示该注解具有继承性。
即如果一个使用了@Inherited 修饰的annotation 类型被用于一个class,则这个annotation 将被用于该class 的子类。

(五)@Retention

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    /**
     * Returns the retention policy.
     * @return the retention policy
     */
    RetentionPolicy value();
}

指定注解生命周期RetentionPolicy
上面已经详细进行了解释

(六)@Target

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    /**
     * Returns an array of the kinds of elements an annotation type
     * can be applied to.
     * @return an array of the kinds of elements an annotation type
     * can be applied to
     */
    ElementType[] value();
}

指定注解作用对象ElementType
上面已经详细进行了解释

(七)@Repeatable

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Repeatable {
    /**
     * Indicates the <em>containing annotation type</em> for the
     * repeatable annotation type.
     * @return the containing annotation type
     */
    Class<? extends Annotation> value();
}

@Repeatable是JDK1.8新加入的,它表示在同一个位置重复相同的注解。在没有该注解前,要想在同一个类型上使用相同的注解需要指定value为数组。
eg:

@FilterPath("/update")
@FilterPath("/add")
public class A {}

三、总结

以上部分结合源码对Java注解进行了较为详细的阐述。重点在于注解、基本元注解以及相关使用场景做了解释。很多部分仅代表自己的观点,如有错误还请各位指正~~

参考文档

https://blog.csdn.net/chenliguan/article/details/78304025
https://www.jianshu.com/p/613e3b1bd842
https://blog.csdn.net/sjh66655/article/details/112901868
https://blog.csdn.net/xtho62/article/details/113816008
https://blog.csdn.net/u014207606/article/details/52291951

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Joshua_yi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值