注解知识点
Java代码中使用注释是为了提升代码的可读性,也就是说,注释是给人看的(对于编译器来说没有意义)。注解可以看做是注释的“强力升级版",它可以向编译器、虚拟机等解释说明一些事情(也就是说它对编译器等工具也是“可读”的)。比如@Override注解,它的作用是告诉编译器它所注解的方法是重写的父类中的方法,这样编译器就会去检查父类是否存在这个方法,以及这个方法的签名与父类是否相同。
也就是说,注解是描述Java代码的代码,它能够被编译器解析,注解处理工具在运行时也能够解析注解。除了向编译器等传递一些信息,我们也可以使用注解生成代码。比如我们可以使用注解来描述我们的意图,然后让注解解析工具来解析注解,以此来生成一些”模板化“的代码。比如Hibernate、Spring等框架大量使用了注解,来避免一些重复的工作。注解是一种”被动“的信息,必须由编译器或虚拟机来“主动”解析它,它才能发挥自己的作用
元注解
元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明
1. @Target
@Target说明了Annotation所修饰的对象范围,取值(ElementType)有:
CONSTRUCTOR:用于描述构造器
FIELD:用于描述域
LOCAL_VARIABLE:用于描述局部变量
METHOD:用于描述方法
PACKAGE:用于描述包
PARAMETER:用于描述参数
TYPE:用于描述类、接口(包括注解类型) 或enum声明
@Target({ElementType.FIELD, ElementType.METHOD})
2. @Retention
@Retention定义了该Annotation的“生命周期”,取值(RetentionPoicy)有:
SOURCE:在源文件中有效(即源文件保留)
CLASS:在class文件中有效(即class保留)
RUNTIME:在运行时有效(即运行时保留)
@Retention(RetentionPolicy.RUNTIME)
3. @Documented
@Documented用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化
Documented是一个标记注解,没有成员
4. @Inherited
@Inherited元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的
如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类
自定义注解
使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。
定义注解格式:
public @interface 注解名 {定义体}
注解参数的可支持数据类型:
1.所有基本数据类型(int,float,boolean,byte,double,char,long,short)
2.String类型
3.Class类型
4.enum类型
5.Annotation类型
6.以上所有类型的数组
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
public @interface SerializedName {
String value();
String[] alternate() default {};
}
注解处理器
1.运行时注解处理器
java.lang.reflect包中的所有API都支持读取运行时Annotation的能力,即属性为@Retention(RetentionPolicy.RUNTIME)的注解。
//获取所有属性
Field[] fields = clazz.getDeclaredFields();
for(Field field : fields){
//根据注解的类型做不同的处理
if(field.isAnnotationPresent(XXX.class)){
//获取该类型的注解
XXX xx = field.getAnnotation(XXX.class);
//获取注解中元素值
xxx.方法名;
}else if(field.isAnnotationPresent(FruitColor.class)){
something
}
2.编译时注解处理器
采用APT(Annotation Processor Tool)
编译时注解处理器编译一个注解时,主要分2步
- 继承AbstractProcessor,实现自己的注解处理器
- 注册处理器,并打包成jar
4个重要方法,其中process是必须实现的抽象方法
init(ProcessingEnvironment processingEnv) 该方法由注解处理器自动调用,其中ProcessingEnvironment类提供了很多有用的工具类:Filter,Types,Elements,Messager等
getSupportedAnnotationTypes() 该方法返回字符串的集合表示该处理器用于处理那些注解
getSupportedSourceVersion() 该方法用来指定支持的Java版本,一般来说我们都是支持到最新版本,因此直接返回SourceVersion.latestSupported()即可
process(Set annotations, RoundEnvironment roundEnv) 该方法是注解处理器处理注解的主要地方,我们需要在这里写扫描和处理注解的代码,以及最终生成的java文件。其中需要深入的是RoundEnvironment类,该用于查找出程序元素上使用的注解