前面我们介绍了注解的概念,也解释了什么是元数据。这篇博客,我们来介绍解释注解的元数据,元注解。Java中有四种元注解:@Retention,@Target,@Documented和@inherited. 接下来,我们一一来介绍这些注解。
- @Retention注解:只能用于修饰一个Annotation定义,用于指定该Annotation的生命周期。@Retention包含一个RetentionPolicy类型的成员变量,使用@Retention注解时必须为该变量成员赋值。下面是这三种保留策略的说明:
- RetentionPolicy.SOURCE: 在源文件(.java文件),即源文件中保留,编译时期注解将被丢弃。
- RetentionPolicy.CLASS: 在class文件中有效,即.class文件中保留。当JVM解释.class字节码时,不会保留该注解。这是默认策略。
- RetentionPolicy.RUNTIME: 在运行时有效,即运行时保留。当运行Java程序时,JVM会保留注解,Java程序可以通过反射获取该注解。
- 自定义注解:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String [] values();
int number();
}
- 演示@Retention(value = RetentionPolicy.RUNTIME)的使用:
import org.junit.jupiter.api.Test;
import java.lang.annotation.Annotation;
public class AnnotationTest1 {
@Test
@MyAnnotation(values = {"value1", "value2"}, number = 10)
public void test1(){
}
@Test
public void test2() throws NoSuchMethodException {
//类Class的对象,表示到加载内存里的运行时类(AnnotationTest1)
Class clazz = AnnotationTest1.class;
//通过方法类对象实例调用getAnnotations()去获取注解数组
Annotation [] annotations = clazz.getMethod("test1", null).getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation.toString());
}
}
}
- 输出:
@org.junit.jupiter.api.Test()
@EnumAndAnnotation.MyAnnotation(values=[value1, value2], number=10)
我们可以看到注解到test1方法的两个注解都被打印了出来。说明不仅我们自定义的@MyAnnotation被@Retention注解了,而且策略为RetentionPolicy.RUNTIME,并且@Test注解也是相同的情况。
-
@Target注解:用于修饰Annotation定义,指定被修饰的Annotation能用于修饰哪些程序元素。@Target包含一个数组成员变量,该值如下(Java 8版本):
TYPE,
FIELD,
METHOD,
PARAMETER,
CONSTRUCTOR,
LOCAL_VARIABLE,
ANNOTATION_TYPE,
PACKAGE,
TYPE_PARAMETER,
TYPE_USE
顾名思义,由名称可知,数组中包含哪些值,就可以注解到对应的地方。 -
@Documented注解: 用于指定被该元注解修饰的Annotation类将被javadoc工具提取成文档。默认情况下,javadoc是不包括注解,@Documented注解必须要和策略为RUNTIME的@Retention注解一起使用。
-
@Inherited注解:被它修饰的Annotation将具有继承性。如果某个类使用了被@Inherited修饰的Annotation,则其子类将自动具有该注解。
-
@Inherited注解的实例代码:
import java.lang.annotation.*;
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface MyAnnotation {
String [] values();
int number();
}
package EnumAndAnnotation;
@MyAnnotation(values = {"value"}, number = 10)
public class Person {
}
class Student extends Person{}
@Test
public void test3(){
Class clazz = Student.class;
Annotation[] annotations = clazz.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation.toString());
}
}
- 输出:
@EnumAndAnnotation.MyAnnotation(values=[value], number=10)
- 即使Student类没有显示地被注解@MyAnnotation,但是它的父类Person被注解,而且@MyAnnotation被@Inherited注解,因此Student类自动有了该注解。