22.4 查看注解信息

22.4 查看注解信息

创建了注解,就可以在程序中使用,注解指定的目标,提供需要的参数,但这还是不会影响到程序的运行。要影响程序,我们要先能查看这些信息。我们主要考虑@Retention为RetentionPolicy.RUNTIME的注解,利用反射机制在运行时进行查看和利用这些信息。

在上一章,我们提到了反射相关类中与注解有关的方法,这里汇总说明下,Class、Field、Method、Constructor中都有如下方法:

1
2
3
4
5
6
7
8
9
//获取所有的注解
public Annotation[] getAnnotations()
//获取所有本元素上直接声明的注解,忽略inherited来的
public Annotation[] getDeclaredAnnotations()
//获取指定类型的注解,没有返回null
public <A extends Annotation> A getAnnotation(Class<A> annotationClass)
//判断是否有指定类型的注解
public boolean isAnnotationPresent(
Class<? extends Annotation> annotationClass)

Annotation是一个接口,它表示注解,具体定义为:

1
2
3
4
5
6
7
public interface Annotation {
boolean equals(Object obj);
int hashCode();
String toString();
//返回真正的注解类型
Class<? extends Annotation> annotationType();
}

实际上,内部实现时,所有的注解类型都是扩展的Annotation。

对于Method和Contructor,它们都有方法参数,而参数也可以有注解,所以它们都有如下方法:

1
public Annotation[][] getParameterAnnotations()

返回值是一个二维数组,每个参数对应一个一维数组。我们看个简单的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class MethodAnnotations {
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
static @interface QueryParam {
String value();
}
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
static @interface DefaultValue {
String value() default "";
}
public void hello(@QueryParam("action") String action,
@QueryParam("sort") @DefaultValue("asc") String sort){
//…
}
public static void main(String[] args) throws Exception {
Class<? > cls = MethodAnnotations.class;
Method method = cls.getMethod("hello",
new Class[]{String.class, String.class});
Annotation[][] annts = method.getParameterAnnotations();
for(int i=0; i<annts.length; i++){
System.out.println("annotations for paramter " + (i+1));
Annotation[] anntArr = annts[i];
for(Annotation annt : anntArr){
if(annt instanceof QueryParam){
QueryParam qp = (QueryParam)annt;
System.out.println(qp.annotationType()
.getSimpleName()+":"+ qp.value());
}else if(annt instanceof DefaultValue){
DefaultValue dv = (DefaultValue)annt;
System.out.println(dv.annotationType()
.getSimpleName()+":"+ dv.value());
}
}
}
}
}

这里定义了两个注解@QueryParam@DefaultValue,都用于修饰方法参数,方法hello使用了这两个注解,在main方法中,我们演示了如何获取方法参数的注解信息,输出为:

1
2
3
4
5
annotations for paramter 1
QueryParam:action
annotations for paramter 2
QueryParam:sort
DefaultValue:asc

代码比较简单,就不赘述了。

定义了注解,通过反射获取到注解信息,但具体怎么利用这些信息呢?我们看两个简单的示例,一个是定制序列化,另一个是DI(依赖注入)容器。