注解的语法
注解是一种接口,但使用 @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 enumboolean showStopper() default false;String assignedTo() default "none";Class<?> testCase() default Void.class;Status status() default Status.UNCONFIRMED;Reference ref() default @Reference(); // an annotation typeString[] 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 annotationpublic @interface Tag {String value() default "";}
@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface Tags { // container annotationTag[] 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); // nullTags 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注解不会过滤相同的值。
