1 注解
注解是放在Java源码的类、方法、字段、参数前的一种标签。
注解本身对代码的逻辑没有任何影响,如何使用注解是由工具决定的,比如编译器可以使用注解,它可以使用JDK定义的注解,注解本身对代码没有影响,但写了注解,编译器可以帮我们检查问题,不写就不检查,JDK定义的常用注解有:
@Override
:让编译器检查该方法是否正确地实现覆写@Deprecated
:告诉编译器该方法已经作废,在别处使用会出现警告@SuppressWarning
:取消警告
1.1 定义注解
使用注解的时候可以传入配置参数,配置参数在创建注解类型时定义,配置参数可以包括:
- 所有基本类型
String
- 枚举类型
- 基本类型的数组
传入配置参数必须是常量而不能是变量,如果缺少某个配置参数将使用默认值,如果只写常量,相当于将该常量赋值给 value
参数,如果只写注解,相当于全部使用默认值。
定义注解的时候,使用 @interface
定义注解
- 注解的参数声明类似声明一个无参数方法
- 可以设定一个默认值
- 推荐把最常用的参数命名为
value
eg:
public @interface Report {
int type() default 0;
String value() default "";
}
1.1.1 元注解
有一些注解可以修饰其他的注解,把这些注解称为元注解。
1.1.1.1 @Target
注解
使用 @Target
注解可以规定被修饰的注解能应用在源码的哪个位置:
ElementType.TYPE
:类或接口ElementType.FIELD
:字段ElementType.METHOD
:方法ElementType.CONSTRUCTOR
:构造方法ElementType.PARAMETER
:方法参数
eg:
@Target({
ElementType.FIELD,
ElementType.METHOD
})
public @interface Report {
int type() default 0;
String value() default "";
}
1.1.1.2 @Retention
注解
@Retention
用于定义被修饰注解的生命周期:
RetentionPolicy.SOURCE
:仅编译期,编译器在编译的时候直接丢弃,比如@Override
RetentionPolicy.CLASS
:仅 class 文件,该注解仅存在 class 文件中,不会被读取,有些工具可以处理 class 文件,这些工具就可以读取这个注解RetentionPolicy.RUNTIME
:仅运行期,在运行期可以通过代码读取该注解
如果没有 @Retention
注解,那么注解本身的生命周期默认为 CLASS
,通常自定义的注解应该都是 RUNTIME
1.1.1.3 Repeatable
注解
Repeatable
注解修饰的注解可以重复注解,比如:
@Repeatable
@Target(ElementType.TYPE`)
public @interface Report {
int type() default 0;
String value() default "";
}
// 重复使用
@Report(type=1)
@Report(type=2)
public class Hello {
}
1.2 处理注解
因为通常写的代码并不涉及到编译器,class 文件中的注解也很少会用到,所以这里处理的注解主要针对的是运行期可以被读取的注解,也就是 Runtime
类型的注解。
如何读取 Runtime
的注解?方法是通过 反射。
因为 Annotaion
也是 class
,所有的 Annotation
都继承自 java.lang,annotation.Annotation
,使用 反射API 就可以获取这些 Annotation
。
使用 反射API 确定一个 Annotation
(注解)是否存在:
Class.isAnnotationPresent(Class)
Field.isAnnotationPresent(Class)
Method.isAnnotationPresent(Class)
Constructor.isAnnotationPresent(Class)
eg:
Class cls = Person.class;
// 判断 @Report 是否存在
cls.isAnnotationPresent(Report.class); // 返回布尔值
使用 反射API 获取一个 Annotation
(注解):
Class.getAnnotation(Class)
Field.getAnnotation(Class)
Method.getAnnotation(Class)
Constructor.getAnnotation(Class)
eg:
class cls = Person.class;
Report report = cls.getAnnotion(Report.class); // 如果不存在,返回 null
int type = report.type();
详情通过反射读取注解,处理注解的代码,可以查看我的github
获取方法参数的
Annotation
比较麻烦,因为一般的方法可能有多个参数,同时参数本身也可以有多个注解,此时使用的是Method.getParemterAnnotations()
方法获取一个Anntation
的二维数组,第一个维度代表的是参数的个数,第二个维度代表的是每个参数本身自带的注解个数。