探秘Java:那些你熟悉又陌生的注解

本文深入讲解Java注解的概念、基础注解及自定义注解的处理方法,包括编译期和运行期处理,并通过示例演示自定义注解的创建与应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、什么是注解

自JDK 5以后,JDK就提供了一种用于描述类、变量、方法和方法参数等的信息的类——注解类。简单理解,可以认为注解类是一种能够被程序识别处理的程序级别的“注释”。

通过注解类,开发人员可以对类、变量、方法或方法参数进行一些特殊的标记和描述,然后在编译期或运行期可以针对这些被特殊标记或描述的类、变量、方法或方法参数进行一些特殊的操作。

从JDK的源码当中可以了解到,所有的注解都是接口 的实现类,但是这个实现的声明并显示地在代码层面进行展示,而需要通过编译后的二进制文件进行观察。

除此以外,还需要注意注解类实际上是一种特殊的接口声明,但是为了和普通的接口声明进行区分,在关键字 前面添加了一个@进行特殊声明。这也从另一个方面说明了注解本身是没有任何处理逻辑的,只是标注了一些元数据信息,至于如何去处理这些元数据信息,则需要通过其他手段进行处理。

二、Java中的基础注解

在Java中提供了两类基础注解以供开发使用和进行自定义注解的扩展,分别是如下两种:

: 用于标记和描述注解最基本信息的注解,是JDK中最基础的注解。对于每个注解都需要指明其保留的时间和生效的上下文这些最基本的信息,JDK原生的元注解则提供了可以用于标注并描述这些信息的注解。具体元注解有以下几种:

: 只存在于源代码中,编译期就会被丢弃。

: 注解会在编译期被写入class文件中,但在运行期会被VM丢弃,是默认的保留策略。

: 注解会一直保存至运行期,即该注解可以通过反射机制获取对应的信息。

: 指明带有该注解的注解将保留多长时间,是最重要的两个元注解之一。所有的注解都需要设置来表明其存活的生命周期,如果不做设置则其保留策略默认为。需要注意的是,一个注解只能设置一个保留策略。具体策略如下:

: 指明带有该注解的注解所适用的上下文,是最重要的两个元注解之一。对于的取值可以参考枚举类,该枚举类提供了注解出现在Java程序的语法位置的简单分类。如果没有设置的情况下,注解可以放置在除了类型以外的其他所有语法位置。

: 官方文档中的解释为:在默认情况下,带有类型的注解将由 javadoc 和类似工具记录。实际上就是在生成javadoc文件时会,带有该注解的注解会出现的文档中作为注释的一部分出现。

: 被注解的注解标记一个类时,该类的子类会自动继承该注解(不需要显示声明)。

: JDK提供的原生的通用注解。以下这些内置注解主要是为了方便开发进行通用场景的处理而提供的,可以理解为是JDK提供的针对某些通用场景设置的标准协议。这里列出最常见的三种内置注解:

: 该注解作用于方法级别,指明了被该注解标注的方法用于覆盖其超类当中声明的相同的方法。

: 指明了被该注解标识的方法、变量等程序元素是即将废弃,不鼓励继续使用的。一般用作版本升级中对不再适用的接口进行标注,提醒使用者使用更好的替代方案。

: 官方文档中的解释为:指示应在带注解的元素(以及带注解的元素中包含的所有程序元素)中抑制指定的编译器警告。简单理解就是,如果你不想看到对应的编译器告警,可以通过这个注解进行告警屏蔽处理。

三、如何处理一个注解

注解与注释最大的区别在于,注解可以通过程序进行读取和操作,注释则不行。根据注解的保留策略,JDK提供了两种方式进行注解的处理:插入式注解处理器和反射机制。下面我们就来具体看下这两种处理方式。

1. 插入式注解处理器

JDK在1.6版本之后提供了一种可以在编译期进行注解读取和处理的能力,即插入式注解处理器,开发可以通过实现JDK的API自定义注解处理器实现干涉编译器的行为。这里不得不提到业界大名鼎鼎的提效神器Lombok,Lombok就是通过这种方法来实现通过注解的方式在编译期生成诸如setter、getter等方法的。

首先来看一下Java编译过程的简图:

解析和填充符号表过程实际上是将源码分析转换成一个抽象语法树(AST)。这里引入百度百科对于抽象语法树的解释:

在计算机科学中,抽象语法树(Abstract Syntax Tree,AST),或简称语法树(Syntax tree),是源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。

而在插入式注解处理器进行注解处理的过程会根据注解对这棵抽象语法树进行读取、修改和填充处理,如果在这一过程中发生了修改语法树的情况,编译器会重新进入解析和填充符号过程,一直循环直到抽象语法树不再发生任何变更。

由于语法树当中的任意元素可以被读取、修改,开发人员就能够将很多需要人工编码的工作通过自定义注解处理器的方式在编译期自动完成这些工作,比如上面的Lombok自动生成setter/getter方法等。

2. 反射机制

除了在编译期通过插入式注解处理器对注解进行处理,我们还可以使用反射机制对注解进行处理,当然这里需要将注解的保留策略设置为 。

运行期间使用反射机制来进行注解的读取、修改和编译期使用插入式注解处理器处理相比会有性能上的损耗,但是结合AOP还是能够很好的实现类似日志打印切面等非程序运行时的业务逻辑处理工作。

四、编写一个自定义注解并处理

这里我们编写一个自定义注解来尝试用插入式注解处理器来处理这个自定义注解。为了使用插入式注解处理器,我们需要创建两个maven项目,注意是两个项目,其中一个为自定义注解处理器项目,一个为测试使用项目。

1. 自定义注解处理器项目

注解 IntegerCheck

自定义注解处理器 IntegerTypeCheckProcessor

pom文件

除了上面的代码,在这个项目中还需要在 路径下创建文件 ,在该文件中写入自定义注解的全限定名。最后执行 进行打包操作。

2. 测试项目

测试类 User

pom文件

由于在这个项目中需要使用对应的自定义注解处理器,所以需要在编译插件中加入对应的注解处理器,然后执行 ,最终执行结果如下:

五、总结

其实从上面的例子可以看到,我们处理的并不是注解,而是注解标识的类、变量、方法等程序中的元素。对于上面列出的两种处理方式,插入式注解处理器更偏向于程序的预处理,比如进行代码生成、命名规范检查等,而对于反射机制则能够在程序运行期间对对象实例进行参数校验、日志打印等处理,两者各有其适用场景。

项目实战:

https://www.yunduoketang.com/article/wangxiao-ruanjian2.html

https://www.yunduoketang.com/article/hudong-jiaoxue-ruanjian3.html

https://www.yunduoketang.com/article/dajian-jiaoyu-pingtai6.html

https://www.yunduoketang.com/article/zhibo-peixun-pingtai5.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值