1. 注解的分类
标准注解
包括以下几种注解成为标准注解,这三种是在JDK5之后包含的标准注解(annotation)。
Overide——表示该函数被覆盖重写
Deprecated——表示该函数或者类被废弃,已经不再维护
SuppressWarnings——表示告诉Java编译器关闭对这些方法、类、成员的警告元注解
元注解表示用来自定义其他注解的注解,有以下四种。注解 用法示例 说明 @Target @Target(ElementType.METHOD) 表示该注解可以用于什么地方,可能的ElementType参数有:
CONSTRUCTOR:构造器的声明
FIELD:域声明(包括enum实例)
LOCAL_VARIABLE:局部变量声明
METHOD:方法声明
PACKAGE:包声明
PARAMETER:参数声明
TYPE:类、接口(包括注解类型)或enum声明@Retention @Retention(RetentionPolicy.RUNTIME) 表示需要在什么级别保存该注解信息。可选的RetentionPolicy参数包括:
SOURCE:注解将被编译器丢弃
CLASS:注解在class文件中可用,但会被VM丢弃
RUNTIME:VM将在运行期间保留注解,因此可以通过反射机制读取注解的信息。@Documented @Documented 将注解包含在Javadoc中 @Inherited @Inherited 允许子类继承父类中的注解 。
- 在元注解基础上自定义的注解
2.自定义注解
没有元素的注解叫做标记注解(mark annotation),下面就是一个标记注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MarkAnnotation {
}
下面的MethodInfo是一个比较完整的注解
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
public @interface MethodInfo {
String author() default "example@example.com";
String date();
int version() default 1;
}
在MethodInfo的实现上有以下几点
- 通过 @interface 定义,注解名即为自定义注解名
- 注解配置参数名为注解类的方法名,且:
a. 所有方法没有方法体,没有参数没有修饰符,实际只允许 public & abstract 修饰符,默认为 public ,不允许抛异常
b. 方法返回值只能是基本类型,String, Class, annotation, enumeration 或者是他们的一维数组
c. 若只有一个默认属性,可直接用 value() 函数。一个属性都没有表示该 Annotation 为 Mark Annotation 可以加 default 表示默认值
注解的可用的类型包括以下几种:所有基本类型、String、Class、enum、Annotation、以上类型的数组形式。元素不能有不确定的值,即要么有默认值,要么在使用注解的时候提供元素的值。而且元素不能使用null作为默认值。注解在只有一个元素且该元素的名称是value的情况下,在使用注解的时候可以省略“value=”,直接写需要的值即可。
3.注解的使用
还是以上面的MethodInfo为例,该注解是一个方法注解。
public Example{
@MethodInfo(author="gaoyan", date="2015-05-30", version=2)
public boolean isGoodExample() {
return true;
}
@MethodInfo(date="2015-05-30")
public boolean isBadExample() {
return false;
}
}
4.注解的解析
- 运行时的Annotation解析
对于@Retention(RetentionPolicy=RUNTIME)、@Target(ElementType.METHOD)的Annotation,可以使用下面的API解析:
method.getAnnotation(AnnotationName.class);
method.getAnnotations();
method.isAnnotationPresent(AnnotationName.class);
其他 @Target 如 Field,Class 方法类似
- getAnnotation(AnnotationName.class) 表示得到该 Target 某个 Annotation 的信息,因为一个 Target 可以被多个 Annotation 修饰
- getAnnotations() 则表示得到该 Target 所有 Annotation
- isAnnotationPresent(AnnotationName.class) 表示该 Target 是否被某个 Annotation 修饰
public static void main(String[] args) {
try {
Class cls = Class.forName("Example");
for (Method method : cls.getMethods()) {
MethodInfo methodInfo = method.getAnnotation(
MethodInfo.class);
if (methodInfo != null) {
System.out.println("method name:" + method.getName());
System.out.println("method author:" + methodInfo.author());
System.out.println("method version:" + methodInfo.version());
System.out.println("method date:" + methodInfo.date());
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
编译时的Annotation解析
编译时 Annotation 指 @Retention 为 CLASS 的 Annotation,甴编译器自动解析。需要做的- 自定义类集成自 AbstractProcessor
- 重写其中的 process 函数
假设 MethodInfo 的 @Retention 为 CLASS,解析示例如下:
@SupportedAnnotationTypes({ "MethodInfo" })
public class MethodInfoProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {
HashMap<String, String> map = new HashMap<String, String>();
for (TypeElement te : annotations) {
for (Element element : env.getElementsAnnotatedWith(te)) {
MethodInfo methodInfo = element.getAnnotation(MethodInfo.class);
map.put(element.getEnclosingElement().toString(), methodInfo.author());
}
}
return false;
}
}
SupportedAnnotationTypes 表示这个 Processor 要处理的 Annotation 名字。
process 函数中参数 annotations 表示待处理的 Annotations,参数 env 表示当前或是之前的运行环境
process 函数返回值表示这组 annotations 是否被这个 Processor 接受,如果接受后续子的 rocessor 不会再对这个 Annotations 进行处理