共计 2597 个字符,预计需要花费 7 分钟才能阅读完成。
Java 语言使用 @interface
语法来定义注解(Annotation
),它的格式如下:
public @interface Report {int type() default 0;
String level() default "info";
String value() default "";
}
注解的参数类似无参数方法,可以用 default
设定一个默认值(强烈推荐)。最常用的参数应当命名为value
。
元注解
有一些注解可以修饰其他注解,这些注解就称为元注解(meta annotation)。Java 标准库已经定义了一些元注解,我们只需要使用元注解,通常不需要自己去编写元注解。
@Target
最常用的元注解是 @Target
。使用@Target
可以定义 Annotation
能够被应用于源码的哪些位置:
- 类或接口:
ElementType.TYPE
; - 字段:
ElementType.FIELD
; - 方法:
ElementType.METHOD
; - 构造方法:
ElementType.CONSTRUCTOR
; - 方法参数:
ElementType.PARAMETER
。
例如,定义注解 @Report
可用在方法上,我们必须添加一个@Target(ElementType.METHOD)
:
@Target(ElementType.METHOD)
public @interface Report {int type() default 0;
String level() default "info";
String value() default "";
}
定义注解 @Report
可用在方法或字段上,可以把 @Target
注解参数变为数组{ElementType.METHOD, ElementType.FIELD}
:
@Target({
ElementType.METHOD,
ElementType.FIELD
})
public @interface Report {...}
实际上 @Target
定义的 value
是ElementType[]
数组,只有一个元素时,可以省略数组的写法。
@Retention
另一个重要的元注解 @Retention
定义了 Annotation
的生命周期:
- 仅编译期:
RetentionPolicy.SOURCE
; - 仅 class 文件:
RetentionPolicy.CLASS
; - 运行期:
RetentionPolicy.RUNTIME
。
如果 @Retention
不存在,则该 Annotation
默认为 CLASS
。因为通常我们自定义的Annotation
都是 RUNTIME
,所以,务必要加上@Retention(RetentionPolicy.RUNTIME)
这个元注解:
@Retention(RetentionPolicy.RUNTIME)
public @interface Report {int type() default 0;
String level() default "info";
String value() default "";
}
@Repeatable
使用 @Repeatable
这个元注解可以定义 Annotation
是否可重复。这个注解应用不是特别广泛。
@Repeatable(Reports.class)
@Target(ElementType.TYPE)
public @interface Report {int type() default 0;
String level() default "info";
String value() default "";
}
@Target(ElementType.TYPE)
public @interface Reports {Report[] value();}
经过 @Repeatable
修饰后,在某个类型声明处,就可以添加多个 @Report
注解:
@Report(type=1, level="debug")
@Report(type=2, level="warning")
public class Hello {
}
@Inherited
使用 @Inherited
定义子类是否可继承父类定义的 Annotation
。@Inherited
仅针对 @Target(ElementType.TYPE)
类型的 annotation
有效,并且仅针对 class
的继承,对 interface
的继承无效:
@Inherited
@Target(ElementType.TYPE)
public @interface Report {int type() default 0;
String level() default "info";
String value() default "";
}
在使用的时候,如果一个类用到了@Report
:
@Report(type=1)
public class Person {
}
则它的子类默认也定义了该注解:
public class Student extends Person {
}
如何定义 Annotation
我们总结一下定义 Annotation
的步骤:
第一步,用 @interface
定义注解:
public @interface Report {
}
第二步,添加参数、默认值:
public @interface Report {int type() default 0;
String level() default "info";
String value() default "";
}
把最常用的参数定义为value()
,推荐所有参数都尽量设置默认值。
第三步,用元注解配置注解:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Report {int type() default 0;
String level() default "info";
String value() default "";
}
其中,必须设置 @Target
和@Retention
,@Retention
一般设置为 RUNTIME
,因为我们自定义的注解通常要求在运行期读取。一般情况下,不必写@Inherited
和@Repeatable
。
小结
Java 使用 @interface
定义注解;
可定义多个参数和默认值,核心参数使用 value
名称;
必须设置 @Target
来指定 Annotation
可以应用的范围;
应当设置 @Retention(RetentionPolicy.RUNTIME)
便于运行期读取该Annotation
。