注解(annotation)不是注释(comment);
注解,是一种元数据(metadata),可为我们在代码中添加信息提供了一种形式化的方法。注解在一定程度上实现了元数据和源代码文件的结合,而不是将元数据保存在外部文档中。
Java SE5 在 java.lang 中定义的三种基本注释:
- @Override
- @Deprecated
- @SuppressWarnings
以及 4 中元注解:
- @Target
- @Retention
- RetentionPolicy.SOURCE – 在编译阶段丢弃。这些注解在编译结束之后就不再有任何意义,所以它们不会写入字节码。@Override, @SuppressWarnings都属于这类注解。
- RetentionPolicy.CLASS – 在类加载的时候丢弃。在字节码文件的处理中有用。注解默认使用这种方式。
- RetentionPolicy.RUNTIME– 始终不会丢弃,运行期也保留该注解,因此可以使用反射机制读取该注解的信息。我们自定义的注解通常使用这种方式。
- @Documented(将此注解包含在 doc 中)
- @Inherited(允许子类继承父类中的注解)
1. 定义注解
可以看到,注解的定义看起来很像接口(@interface)的定义。事实上,与其他任何 java 接口一样,注解也会被编译成 .class 文件:
@Target(ElementType.METHOD) // java.lang.annotation.ElementType/Target
@Retention(RetentionPolicy.RUNTIME) // java.lang.annotation.Retention/RententionPolicy;
public @interface Test {}
定义注解时,会需要一些元注解(meta-annotation),比如上例的 @Target 和 @Retention。
- @Target 用来定义你的注解将应用在什么地方
- 一个方法(@Target(ElementType.METHOD)),
- 或是一个域(成员变量,@Target(ELEMENTTYPE.FIELD))
- ElementType.CONSTRUCTOR
- ElementType.LOCAL_VARIABLE
- ElementType.PACKAGE
- ElementType.TYPE
- ElementType.PARAMETER
- @Retention 用来定义该注解在哪一级别可用:
- SOURCE:源代码中;
- CLASS:类文件中;
- RUNTIME:运行时;
在注解上,一般也会包含一些元素以表示某些值。当搜集分析处理注解时,程序或者工具可以利用这些值(没有元素的注解称为标记注解 marker annotation,也即仅起到标记作用,如上例的 @Test)。注解的元素看起来就像接口的方法,唯一的区别你可以为其指定默认值。
2. 注解的应用
如下为一个用来跟踪项目用例的注解。如果一个方法或一组方法实现了某个用例的需求,那么程序员可以为此方法加上注解。项目经理便可通过计算已经实现的用例,以掌握项目的进展。
// UseCase.java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UseCase {
public int id();
public String description() default "no description";
}
// PasswordUtils
public class PasswordUtils {
@UseCase(id = 47, description = "password must contains at least one numeric")
public boolean validatePassword(String password) {
return password.matches("\\w*\\d\\w*");
}
@UseCase(id = 48)
public String entryptPassword(String password) {
return new StringBuilder(password).reverse().toString();
}
@UseCase(id = 49, description = "new password can't equal previously used ones")
public boolean checkForNewPassword(List<String> prevPasswords, String password) {
return prevPasswords.contains(password);
}
}