注解
定义在类、方法、字段 、参数前的”注释“。注解(annotation
)可以被编译器打包进class文件。
元注解
有一些注解可以修饰其他注解,这些注解就称为元注解(meta annotation
)。常用 元注解有@Retention、@ Target、@ Inherited、@ Documented
@Retention
RetentionPolicy的枚举,表示注解在何时生效:
- SOURCE 类型的注解在编译期就被丢掉了;如@Override。
- CLASS 类型的注解仅保存在class文件中,它们不会被加载进JVM;如@Nullable。
- RUNTIME 类型的注解会被加载进JVM,并且在运行期可以被程序读取。
如果@Retention不存在,则该Annotation默认为CLASS。因为如果我们自定义的Annotation都是RUNTIME,务必要加上@Retention(RetentionPolicy.RUNTIME)这个元注解。
@Target
标明了注解的适用范围,对应ElementType枚举。
- 类或接口:
ElementType.TYPE
; - 字段:
ElementType.FIELD
; - 方法:
ElementType.METHOD
; - 构造方法:
ElementType.CONSTRUCTOR
- 方法参数:
ElementType.PARAMETER
。
@Inherited
注解所作用的类,在继承时默认无法继承父类的注解。除非注解声明了 @Inherited。同时Inherited声明出来的注,只对类有效,对方法/属性无效。并且仅针对class
的继承,对interface
的继承无效。
@Document
注解标记的元素,Javadoc工具会将此注解标记元素的注解信息包含在javadoc中。默认,注解信息不会包含在Javadoc中。
定义注解
- public @interface 注解名 {方法参数}
1 | public Subscribe { |
- 添加参数、默认值:
1 | ThreadMode threadMode() default ThreadMode.POSTING; |
- 元注解配置注解
1 | (RetentionPolicy.RUNTIME) |
注解 in kotlin
@Target
指定可以用该注解标注的元素的可能的类型(类、函数、属性、表达式等);@Retention
指定该注解是否存储在编译后的 class 文件中,以及它在运行时能否通过反射可见 (默认都是 true);@Repeatable
允许在单个元素上多次使用相同的该注解;@MustBeDocumented
指定该注解是公有 API 的一部分,并且应该包含在生成的 API 文档中显示的类或方法的签名中。
1 |
|
运行时注解
运行时注解@Retention(RetentionPolicy.RUNTIME)
,大多数时候是在运行时使用反射来实现所需效果。
Java提供的使用反射API读取Annotation
的方法包括:
判断某个注解是否存在于Class
、Field
、Method
或Constructor
:
X.isAnnotationPresent(Class)
使用反射API读取Annotation:
X.getAnnotation(Class)
例如:
1 | val methods = clazz.javaClass.declaredMethods |
编译时注解
注解处理器(annotation processor
)是javac的一个工具,它用来在编译时扫描和处理注解。你可以对自定义注解,并注册相应的注解处理器,用于处理你的注解逻辑。
创建java or kotlin Library
, 实现一个自定义注解处理器(AbstractProcessor
),至少重写四个方法,并且注册你的自定义Processor。
1 | override fun init(processingEnv: ProcessingEnvironment) { |
注册Processor
AbstractProcessor实现之后不能直接使用,需要注册之后才能运行,有两种方式:
- 手动注册
在实现AbstractProcessor的项目中添加resources/META-INF
文件夹,并在META-INF下添加一个名称为javax.annotation.processing.Processor
的文本文件,在里面写入实现AbstractProcessor类的全名vip.lovek.processor.EventBusProcessor
- 自动注册
使用google提供的AutoService主动注册。在AbstractProcessor实现类上加上注解:
1 | class) (Processor:: |
自动注册方式在kotlin中有bug,如果不能自动生成,推荐手动注册。
生成代码
AbstractProcessor中提供了生成代码的辅助类:Filer。 在ProcessingEnvironment中,生成代码就是一个创建文件写入文本内容的过程。生成java源码有很名的javapoet框架,在kotlin中运行Processor时kapt来替代annotationProcessor, 也有kotlinpoet框架来代替javapoet。
1 | private fun createFile() { |
生成代码内容为:
1 | package vip.lovek.sharingan |