知识点

注解那些事儿!

2019-03-12  本文已影响29人  s1991721

引言

在java开发中你是否留意到随处可见的以下代码

是否习以为常,认为都是系统自动添加的就忽略它们。

为什么在发现代码有警告时,加上@SuppressWarnings后警告就消失了?

引用某些三方库后,又会出现Java中从未见过的注解。只有按照API说明的方式编写注解信息,才能正常运行,为什么?

本篇就来聊聊注解那些事!

注解

什么是注解

注解的定义

首先明确注解也是类的一种,同class、interface,也会生成注解对象,只不过生成的注解对象依附在注解的对象上,不易察觉

定义注解的关键字是@interface

注解的作用

它的作用就是标记元素

何为元素?

代码中可见的有实际意义的单元即元素

元素有哪些

对应关系

以上是常见元素的对应关系图

既然是标记,就会有标记时长,不然就成永久标记,不符合设计思想有始有终

使用周期

一般类的使用周期:

而注解的使用周期是可定义的,通过@Retention关键字,定义注解的使用周期

RetentionPolicy

不同的周期声明,注解存在的位置也不同

编辑时(SOURCE):仅存在于源文件
编译时(CLASS):存在于源文件和字节码文件
运行时(RUNTIME):存在于源文件、字节码文件及JVM内存

为什么@Retention能够修饰注解,它自己不是注解吗?

元注解

这里就要引出元注解的概念,修饰注解的注解称为元注解。

用来声明注解所要标记的元素类型、使用周期等信息

元注解的目标元素类型为ANNOTATION_TYPE即注解类型

有了注解类型和周期,那注解标记对象这一行为有什么意义呢?

标记的作用

针对配置功能,有两种截然不同的处理方式:

这里来看看编译时处理是怎样应用注解的

注解处理器

注解的要求

因为处理的时机是在编译时,所以注解的使用周期最少也要坚持到编译时,这也就要求了注解处理器所处理的注解必须有如下声明

处理器的要求

注解不止是一家定义使用的,Java有它自己的注解,Retrofit这种三方库也有自己定义的注解。注解的定义规范上述已经有了,那处理注解也要有一套规范,这就是AbstractProcessor。
所有自定义的注解处理器都必须继承自AbstractProcessor,实现其方法处理注解

注解处理器实际也是个类,那编译器在成百上千的类面前先执行谁呢?思考下Java程序的启动,它会找出实现了main方法的类作为程序入口,以此来运行整个程序逻辑,这是规定死的。同样注解处理器也要被明确优先执行,以防使用注解时发现注解还没有被处理。

注册

处理

注解有了也注册了注解处理器,接下来注解处理器便开始工作

明确工作范围

注解处理器需要明确当前工作环境Java的版本,注解是Java1.5才引入的概念,所以注解处理器肯定在此之后。

常规写法

返回最新支持的版本,既然是重写,看看父类

AbstractProcessor

父类方法中获取@SupportedAnnotationTypes的注解对象,取其值作为支持的Java的版本,因此也可以这么写,替代重写getSupportedSourceVersion方法

明确观察对象

注解处理器不是处理所有的注解,它只关心它所关心的

重写getSupportedAnnotationTypes方法,返回需要处理的注解类型

既然是重写,看看父类

AbstractProcessor

与getSupportedSourceVersion方法相同的设计模式,可以通过注解设置观察对象

注意:重写优先于注解

process

工作条件已经明确了开始工作!

process方法是主要处理方法,共两个参数:set中存储着将要处理的注解类型,就是getSupportedAnnotationTypes所返回的注解类型、roundEnvironment理解为运行环境,可以获取程序运行中的信息。

以仿ButterKnife的代码为例

注解的很清楚了,找出被BindView注解的变量,取其上注解对象的值,并和对象一起存到MainActivity唯一确定的proxy对象中

有了注解配置的所有信息,接下来就可以为所欲为了

直接返回Java字符串,生成的.java文件内容就是字符串内容

这种生成Java文件的方法很容易出错, square公司的JavaPoet库是很好的选择,具体用法在GitHub上有官方介绍

上一篇下一篇

猜你喜欢

热点阅读