注解的语法
注解是一种接口,但使用 @interface
修饰符修饰。所有的注解(接口)都隐性的继承自 java.lang.annotation.Annotation
接口,
注解内的元素类型可以是以下任何一种:
- 基本数据类型(byte,short,int,long,char,double,float,boolean)
- String
- Class
- 枚举
- 注解
- 数组
下面代码的声明都是合法的:
public @interface BugReport {
enum Status {UNCONFIRMED, CONFIRMED, FIXED, NOTABUG}; // an enum
boolean showStopper() default false;
String assignedTo() default "none";
Class<?> testCase() default Void.class;
Status status() default Status.UNCONFIRMED;
Reference ref() default @Reference(); // an annotation type
String[] reportedBy();
}
标准注解
在 java.long
、 java.lang.annotation
和 javax.annotation
包中定义了一些标准注解,其中 5 个是元注解。
注解 | 适用范围 | |
---|---|---|
普通 注解 |
Deprecated | All |
SafeVarargs | 除了包和注解都适用 | |
Override | 方法 | |
FunctionalInterface | 接口 | |
PostConstruct | 方法 | |
PreDestory | 方法 | |
Resource | 类、接口、方法、属性 | |
Resources | 类、接口 | |
Generated | All | |
元注解 | Target | 注解 |
Retention | 注解 | |
Documented | 注解 | |
Inherited | 注解 | |
Repeatable | 注解 |
元注解
@Target
@Target
注解用于限定注解的适用范围,需要传入一个 ElementType
枚举类的值。
Element Type | Annotation Applies To | |
---|---|---|
1 | ANNOTATION_TYPE | Annotation type declarations |
2 | PACKAGE | Packages |
3 | TYPE | Classes (including enum) and interfaces (including annotation types) |
4 | METHOD | Methods |
5 | CONSTRUCTOR | Constructors |
6 | FIELD | Fileds (including enum constants) |
7 | PARAMETER | Method or constructor parameters |
8 | LOCAL_VARIABLE | Local variables |
9 | TYPE_PARAMETER | Type parameters |
10 | TYPE_USE | Uses of a type |
如果一个注解没有 @Target
限制,可以用于任何地方。
@Retention
@Retention
注解用于表示一个注解保存到哪个阶段, RetentionPolicy
枚举类提供了以下 3 种级别:
Retention Policy | Description | |
---|---|---|
1 | SOURCE | Annotation are not included in calss files |
2 | CLASS | Annotations are included in class files, but the jvm need not load them |
3 | RUNTIME | Annotations are included in class files and loaded by the jvm. They are available through the reflection API |
默认是 RetentionPolicy.CLASS
。
@Documented
@Documented
注解用于如 Javadoc 之类的文档生成工具,这里不展开解释。
@Inherited
@Inherited
注解仅作用于类,默认情况下,父类的普通注解不能被子类继承,但如果父类的注解被 @Inherited
注解修饰,则该注解可以被子类自动继承。
@Repeatable
Java 8 新增了一个 @Repeatable
元注解,使得某些注解可在同一元素上修饰多次。@Repeatable
元注解需要传入一个 container annotation。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Tags.class) // 需要传入一个 container annotation
public @interface Tag {
String value() default "";
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Tags { // container annotation
Tag[] value(); // 返回类型必须是对应的注解数组,方法名必须是 value
}
使用自定义的 @Tag
注解并测试,代码如下所示:
public class AnnotationClass {
@Tag("father")
@Tag("father") // 注意标注了两次相同的值
@Tag("teacher")
public void getTags() {}
}
try {
Method method = AnnotationClass.class.getDeclaredMethod("getTags");
Tag tag = method.getAnnotation(Tag.class); // null
Tags tags = method.getAnnotation(Tags.class);
// [@Tag(value=father), @Tag(value=father), @Tag(value=teacher)]
System.out.println(Arrays.toString(tags.value()));
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
对于上述代码需要主语两点:
- 直接用反射获取被
@Repeatable
修饰的注解(如@Tag
)返回值为null
; @Repeatable
注解不会过滤相同的值。