注解在一定程度上是在把元数据与源代码文件结合在一起,而不是保存在外部文档。
定义注解
注解的定义看起来很像接口的定义。
例:
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test{}
除了@符号以外,@Test的定义很像一个空的接口。定义注解时,会需要一些元注解(meta-annotation),如@Target和@Retention。@Target用来定义你的注解将应用于什么地方。@Retention用来定义该注解在哪一个级别可用,在源代码中(SOURCE)、类文件中(CLASS)、或者运行时(RUNTIME)。
元注解
JAVA目前只内置了三种标准注解,以及四种元注解。元注解专职负责注解其他的注解:
@Target 表示该注解可以用于什么地方。可能的ElementType参数包括
CONSTRUCTOR:构造器的声明
FIELD:域声明(包括enum实例)
LOCAL_VARIABLE:局部变量声明
METHOD:方法声明
PACKAGE:包声明
PARAMETER:参数声明
TYPE:类、接口(包括注解类型)或enum声明。
@Retention 表示需要在什么级别保存该注解信息。可选的RetentionPolicy参数包括:
SOURCE:注解将被编译器丢弃
CLASS:注解在class文件中可用,但会被VM丢弃。
RUNTIME:VM将在运行期也保留注解,因此可以通过反射机制读取注解的信息。
@Documented 将此注解包含在Javadoc中。
@Inherited 允许子类继承父类中的注解。
编写注解处理器
使用注解的过程中,很重要的一个部分就是创建与使用注解处理器。JAVA扩展了反射机制的API,以帮助程序员构造这类工具。同时,它还提供了一个外部工具apt帮助程序员解析带有注解的JAVA源代码。
例
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UseCase{
public int id();
public String description() default "no description";
}
import java.util.*;
public class PasswordUtils{
@UseCase(id=47, description="Passwords must contain at least one numeric")
public boolean validatePassword(String password){
return (password.matches("\\w*\\d\\w*"));
}
@UseCase(id=48)
public String encryptPassword(String password){
return new StringBuilder(password).reverse().toString();
}
@UseCase(id=49, description="New passwords can't equal previously used ones")
public boolean checkForNewPassword(List<String> prePasswords, String password){
return !prevPasswords.contains(password);
}
}
import java.lang.reflect.*;
import java.util.*;
public class UseCaseTracker{
public static void trackUseCases(List<Integer> useCases, Class<?> cl){
for(Method m : cl.getDeclaredMethods()){
UseCase uc = m.getAnnotation(UseCase.class);
if(uc != null){
System.out.println("Found Use Case:" + uc.id() + " " + uc.description());
useCases.remove(new Integer(uc.id()));
}
}
}
public static void main(String[] args){
List<Integer> useCases = new ArrayList<Integer>();
Collection.addAll(useCases,47,48,49,50);
trackUseCases(useCases, PasswordUtils.class);
}
}
注解元素
注解元素可用的类型如下所示:
所有基本类型(int,float,boolean等)
String
Class
enum
Annotation
以上类型的数组
默认值的限制
元素不能有不确定的值。也就是说,元素必须要么具有默认值,要么在使用注解时提供元素的值。