第二个元注解: @Retention 参数 RetentionPolicy。有了前面的经验这个注解理解起来就简单多了,并且幸运的是这个注解还没有特殊的属性值。 简单演示下如何使用:
package com.tmser.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
/*
* 定义注解 Test
* 首先使用ElementType.TYPE
* 运行级别定为 运行时,以便后面测试解析
*/
@Target(ElementType.PACKAGE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestA {
}
View Code
第三和第四个元注解就不再举例了。比较简单,也没有值,相信看过上面的解释也就清楚了。下面我们还是继续来深入的探讨下注解的使用。上面的例子都非常简单,注解连属性都没有。ok,下面我们就来定义一个有属性的注解,并在例子程序中获取都注解中定义的值。
开始之前将下定义属性的规则:
@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。
代码:
/*
* 定义注解 Test
* 为方便测试:注解目标为类 方法,属性及构造方法
* 注解中含有三个元素 id ,name和 gid;
* id 元素 有默认值 0
*/
@Target({TYPE,METHOD,FIELD,CONSTRUCTOR})
@Retention(RetentionPolicy.RUNTIME)
public @interface TestA {
String name();
int id() default 0;
Class<Long> gid();
}
View Code
下面改下我们的测试类:
package com.tmser.annotation;
import java.util.HashMap;
import java.util.Map;
/**
* 这个类专门用来测试注解使用
* @author tmser
*/
@TestA(name="type",gid=Long.class) //类成员注解
public class UserAnnotation {
@TestA(name="param",id=1,gid=Long.class) //类成员注解
private Integer age;
@TestA (name="construct",id=2,gid=Long.class)//构造方法注解
public UserAnnotation(){
}
@TestA(name="public method",id=3,gid=Long.class) //类方法注解
public void a(){
Map<String,String> m = new HashMap<String,String>(0);
}
@TestA(name="protected method",id=4,gid=Long.class) //类方法注解
protected void b(){
Map<String,String> m = new HashMap<String,String>(0);
}
@TestA(name="private method",id=5,gid=Long.class) //类方法注解
private void c(){
Map<String,String> m = new HashMap<String,String>(0);
}
public void b(Integer a){
}
}
View Code
下面到了最重要的一步了,就是如何读取我们在类中定义的注解。只要读取出来了使用的话就简单了。
jdk1.5 既然增加了注解,肯定就增加了相关读取的api
在java.lang.reflect包中新增了AnnotatedElement接口,JDK源码如下:
public interface AnnotatedElement {
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass);
<T extends Annotation> T getAnnotation(Class<T> annotationClass);
Annotation[] getAnnotations();
Annotation[] getDeclaredAnnotations();
}
View Code
- isAnnotationPresent:判断是否标注了指定注解
- getAnnotation:获取指定注解,没有则返回null
- getAnnotations:获取所有注解,包括继承自基类的,没有则返回长度为0的数组
- getDeclaredAnnotations:获取自身显式标明的所有注解,没有则返回长度为0的数组
package com.tmser.annotation;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class ParseAnnotation {
/**
* 简单打印出UserAnnotation 类中所使用到的类注解
* 该方法只打印了 Type 类型的注解
* @throws ClassNotFoundException
*/
public static void parseTypeAnnotation() throws ClassNotFoundException {
Class clazz = Class.forName("com.tmser.annotation.UserAnnotation");
Annotation[] annotations = clazz.getAnnotations();
for (Annotation annotation : annotations) {
TestA testA = (TestA)annotation;
System.out.println("id= \""+testA.id()+"\"; name= \""+testA.name()+"\"; gid = "+testA.gid());
}
}
/**
* 简单打印出UserAnnotation 类中所使用到的方法注解
* 该方法只打印了 Method 类型的注解
* @throws ClassNotFoundException
*/
public static void parseMethodAnnotation(){
Method[] methods = UserAnnotation.class.getDeclaredMethods();
for (Method method : methods) {
/*
* 判断方法中是否有指定注解类型的注解
*/
boolean hasAnnotation = method.isAnnotationPresent(TestA.class);
if (hasAnnotation) {
/*
* 根据注解类型返回方法的指定类型注解
*/
TestA annotation = method.getAnnotation(TestA.class);
System.out.println("method = " + method.getName()
+ " ; id = " + annotation.id() + " ; description = "
+ annotation.name() + "; gid= "+annotation.gid());
}
}
}
/**
* 简单打印出UserAnnotation 类中所使用到的方法注解
* 该方法只打印了 Method 类型的注解
* @throws ClassNotFoundException
*/
public static void parseConstructAnnotation(){
Constructor[] constructors = UserAnnotation.class.getConstructors();
for (Constructor constructor : constructors) {
/*
* 判断构造方法中是否有指定注解类型的注解
*/
boolean hasAnnotation = constructor.isAnnotationPresent(TestA.class);
if (hasAnnotation) {
/*
* 根据注解类型返回方法的指定类型注解
*/
TestA annotation =(TestA) constructor.getAnnotation(TestA.class);
System.out.println("constructor = " + constructor.getName()
+ " ; id = " + annotation.id() + " ; description = "
+ annotation.name() + "; gid= "+annotation.gid());
}
}
}
public static void main(String[] args) throws ClassNotFoundException {
parseTypeAnnotation();
parseMethodAnnotation();
parseConstructAnnotation();
}
}
View Code
先别说话,运行:
id= "0"; name= "type"; gid = class java.lang.Long
method = c ; id = 5 ; description = private method; gid= class java.lang.Long
method = a ; id = 3 ; description = public method; gid= class java.lang.Long
method = b ; id = 4 ; description = protected method; gid= class java.lang.Long
constructor = com.tmser.annotation.UserAnnotation ; id = 2 ; description = construct; gid= class java.lang.Long
View Code
看到了吧,我们定义的注解都完整的输出了,你要使用哪个,直接拿去用就好了。
为了不让这篇文章打开太慢,我省略了类属性注解,及参数注解的解析。其实都大同小异。
另外,我也没有举使用例子。因为我认为好的教程是讲的详细的同时,还会留有扩展。如果我全部写出来,而你只是学习的话,那基本不会自己去动脑了,而是复制粘贴运行一遍完事。
最后提醒下:
1. 要用好注解,必须熟悉java 的反射机制,从上面的例子可以看出,注解的解析完全依赖于反射。
2. 不要滥用注解。平常我们编程过程很少接触和使用注解,只有做设计,且不想让设计有过多的配置时。
疑问:
ElementType. ANNOTATION_TYPE:注解类型,到底什么作用,我发现即使不使用这个类型,我们自定义的注解也可以用来注释其他注解(eclipse 报错,但仍可以编译,也仍可以在测试类中读取出报错的注解,使用TYPE编译器都不报错),难道只是标示注解是个元注解,知道的麻烦告知一下。
(完)