Java注解基本介绍 二
注解与反射机制
前面经过反编译后,我们知道Java所有注解都继承了Annotation接口,也就是说Java使用Annotation接口代表注解元素,该接口是所有Annotation类型的父接口。
同时为了运行时能准确获取到注解的相关信息,Java在java.lang.reflect反射包下新增了AnnotatedElement接口,它主要用于表示目前正在JVM中运行的程序中已使用注解的元素,通过该接口提供的方法可以利用反射技术动态地读取注解的信息
如反射包的Constructor类、Field类、Method类、Package类和Class类都实现了AnnotatedElement接口,它们的含义如下:
- Class:类的Class对象定义
- Constructor:代表类的构造器定义
- Field:代表类的成员变量定义
- Method:代表类的方法定义
- Package:代表类的包定义
下面是AnnotatedElement中相关的API方法,以上5个类都实现以下的方法
getAnnotation(Class annotationClass) 该元素如果存在指定类型的注解,则返回这些注解,否则返回 null
getAnnotations() 返回此元素上存在的所有注解,包括从父类继承的
isAnnotationPresent(Class annotationClass) 如果指定类型的注解存在于此元素上,则返回 true,否则返回 false
getDeclaredAnnotations() 返回直接存在于此元素上的所有注解,注意,不包括父类的注解,调用者可以随意修改返回的数组;这不会对其他调用者返回的数组产生任何影响,没有则返回长度为0的数组
@DocumentedTest1
class TestA { }
@DocumentedTest2
public class DocumentTest extends TestA{
public static void main(String[] args) {
try {
//1、使用类加载器加载类
Class clazz = Class.forName("com.craig.DocumentTest");
//Class<?> clazz1 = Student.class;
// 获取类上的注解有以下几种方式
// 获取类上的注解不包含继承
Annotation[] annotations1 = clazz.getDeclaredAnnotations();
// 获取类上的所有注解,包含继承父类的注解
Annotation[] annotations2 = clazz.getAnnotations();
// 获取类上指定类型的注解
Annotation annotation1 = clazz.getAnnotation(DocumentedTest1.class);
// 2、类上面是否存在DocumentedTest的注解
boolean isExist = clazz.isAnnotationPresent(DocumentedTest1.class);
if (isExist) {
// 3、存在则获取注解实例
DocumentedTest1 documentedTest1 = (DocumentedTest1) clazz.getAnnotation(DocumentedTest1.class);
System.out.println(documentedTest1.toString());
}
// 获取DocumentTest类的所有方法并遍历它们
Method[] methods = clazz.getMethods();
for (Method method : methods) {
// 方法上是否存在指定类型注解
boolean isMethodExist = method.isAnnotationPresent(DocumentedTest1.class);
if (isMethodExist) {
// 存在则获取该注解
DocumentedTest1 annotation = method.getAnnotation(DocumentedTest1.class);
System.out.println(annotation.toString());
}
}
for (Method method : methods) {
// 获取方法上所有的注解并遍历这些注解
Annotation[] annotations = method.getAnnotations();
for (Annotation annotation : annotations) {
// 获取类型匹配的注解
if (annotation instanceof DocumentedTest1) {
DocumentedTest1 description = (DocumentedTest1) annotation;
System.out.println(description.toString());
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
java8中新增的元注解@Repeatable
元注解@Repeatable是JDK1.8新加入的,它表示在同一个位置重复相同的注解。在没有该注解前,一般是无法在同一个类型上使用相同的注解的
//Java8前无法这样使用
@FilterPath("/web/update")
@FilterPath("/web/add")
public class A {}
如果想要实现类似的功能,需要定义参数类型为数组来接收。但是在Java8之后使用这个注解就可以解决
@Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited //添加可继承元注解
@Repeatable(FilterPaths.class) // 参数指定接收的class
public @interface FilterPath{
String value();
}
@Target(ElementType.TYPE)
@Inherited //添加可继承元注解
@Retention(RetentionPolicy.RUNTIME)
@interface FilterPaths {
FilterPath[] value();
}
@FilterPath("/test1/1")
@FilterPath("/test1/2")
@FilterPath("/test1/3")
class Test1{ }
可以简单理解为通过使用@Repeatable后,将使用@FilterPaths注解作为接收同一个类型上重复注解的容器,而每个@FilterPath则负责保存指定的路径串。
