使用注解
使用注解修饰了类、方法、成员变量等成员之后,这些注解不会自己生效,必须由开发者提供相应的工具来提取并处理注解信息。
就像 xml 配置文件一样,你配置了并不会自己生效,需要有工具来读取他。
Java 使用 java.lang.annotation.Annotation 接口来代表程序元素前面的注解,该接口是所有注解的父接口。
AnnotatedElement
Java 5 在 java.lang.reflect 包下新增了 AnnotatedElement 接口,该接口代表程序中可以接受注解的程序元素。
该接口主要有如下几个实现类:
- Class:类定义。
- Constructor:构造器定义。
- Field:类的成员变量定义。
- Method:类的方法定义。
- Package:类的包定义。
public final class Class<T> implements java.io.Serializable,
GenericDeclaration,
Type,
AnnotatedElement {
只有当定义注解时使用了@Retention(RetentionPolicy.RUNTIME)修饰,该注解才会在运行时可见,JVM才会在装载*.class文件时读取保存在class文件中的注解信息。
AnnotatedElement 接口是所有程序元素(如Class、Method、Constructor等)的父接口,所以程序通过反射获取了某个类的AnnotatedElement 对象(如Class、Method、Constructor等)之后,程序就可以调用该对象的如下几个方法来访问注解信息。
AnnotatedElement 方法
<T extends Annotation> T getAnnotation(Class<T> annotationClass);
返回该程序元素上存在的、指定类型的注解,如果该类型的注解不存在,则返回null。
default <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass)
该方法尝试获取直接修饰该程序元素、指定类型的注解。如果该类型的注解不存在,则返回null。
Annotation[] getAnnotations();
返回该程序元素上存在的所有注解。
Annotation[] getDeclaredAnnotations();
返回直接修饰该程序元素的所有注解。
default boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
return getAnnotation(annotationClass) != null;
}
判断该程序元素上是否存在指定类型的注解,如果存在则返回true,否则返回false。
default <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass)
该方法的功能与前面介绍的 getAnnotation() 方法基本相似。但由于Java 8增加了重复注解功能,因此需要使用该方法获取修饰该程序元素、指定类型的多个注解。
default <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass)
该方法的功能与前面介绍的 getDeclaredAnnotations() 方法基本相似。但由于Java 8增加了重复注解功能,因此需要使用该方法获取直接修饰该程序元素、指定类型的多个注解。
使用
自定义两个注解
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyTest {
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyTag {
String name();
int age();
}
使用注解
public class MyInfo {
@MyTest
@MyTag(name = "hb", age = 23)
public void info() {
System.out.println("yyds");
}
}
获取 info 的所有注解
public class Test {
public static void main(String[] args) {
try {
Annotation[] annotations = Class.forName("com.rrz.MyInfo").getMethod("info").getAnnotations();
System.out.println(Arrays.toString(annotations));
} catch (Exception e) {
e.printStackTrace();
}
}
}
结果
访问注解元数据
如果需要获取某个注解里的元数据,则可以将注解强制类型转换成所需要的注解类型,然后通过注解对象的抽象方法来访问这些元数据。
public class Test {
public static void main(String[] args) {
try {
Annotation[] annotations = Class.forName("com.rrz.MyInfo").getMethod("info").getAnnotations();
Arrays.stream(annotations).forEach(annotation -> {
if (annotation.annotationType().equals(MyTag.class)) {
System.out.println("name: " + ((MyTag)annotation).name());
System.out.println("age: " + ((MyTag)annotation).age());
}
if (annotation.annotationType().equals(MyTest.class)) {
System.out.println("MyTest 是一个标记注解,没有元数据");
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}
注意:
为了获得程序中的程序元素(如Class、Method等),必须使用反射知识,