什么是注解?
注解(也被称为元数据)为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便地使用这些数据。
注解定义
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DBTable {
public String name() default "";
}
除了@符号以外,@DBTable注解的定义很像一个接口。定义注解时,会需要一些元注解,如@Target,@Retention。在注解中一般都会包含一些元素用来表示某些值。当分析处理注解时,程序或者工具可以利用这些值。注解的元素看起来就像接口的定义,唯一的区别就是你可以为其指定默认值。
以下是4种元注解,元注解专职负责注解其他的注解。
名称 | Servlet版本 |
---|---|
@Taget | 表示该注解可以用在什么地方。在括号中设置ElementType,其中可能的参数包括: CONSTRUCTOR : 构造器的声明 FIELD : 字段的声明 LOCAL_VARIABLE : 局部变量的声明 METHOD : 方法的声明 PACKAGE : 包声明 PARAMETER : 参数声明 TYPE : 类、接口(包括注解类型)或enum声明 |
@Retention | 表示需要在什么级别保存注解信息。可选的RetentionPolicy参数包括 SOURCE : 注解将被编译器丢弃。 CLASS : 注解在class文件中可用,但会被VM丢弃。 RUNTIME : VM将在运行期也保留注解, 因此可以通过反射机制读取注解的信息。 |
@Documented | 此注解包含在Javadoc中。 |
@Inherited | 此注解允许子类继承父类中的注解 |
注解的使用
下面是一个简单的注解,我们可以用它来跟踪一个项目中的用例。如果一个方法或一组方法实现了某个用例的需求,那么程序员可以为此方法加上该注解。于是,项目经理通过计算已经实现的用例,就可以很好地掌控项目的近战。而如果要更新或修改系统的业务逻辑,则维护该项目的开发人员也可以很容易地在代码中找到对应的用例。
package com.rains.annotation.usecase;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UseCase {
int id() ;
String description() default "no decription";
}
示例中该注解带有元注解@Target(ElementType.METHOD),表示该注解是用于方法上, id和description类似方法定义。description元素有一个默认值,如果在注解某个方法时没有给出decription的值,则该注解的处理器就会使用此元素默认的值。
在下面的方法中,有三个方法被注解为用例:
package com.rains.annotation.usecase;
import com.sun.tools.javac.util.List;
/**
* Created by Rains on 2016/8/24.
*/
public class PasswordUtil {
@UseCase(id = 1 , description = "密码必须包含一个数字")
public boolean validatePassword(String password){
return password.matches("\\w*\\d\\w*");
}
@UseCase(id = 2)
public String encryptPassword(String password){
return new StringBuilder(password).reverse().toString();
}
@UseCase(id= 3 ,description = "新密码不能跟旧密码一样!")
public boolean checkForNewPassword(List<String> prePasswords , String password){
return !prePasswords.contains(password);
}
}
注解的元素在使用时表现为键-值对的形式,并且需要放置在@UseCase声明之后的括号内。
在encryptPassword()方法的注解中并没有给description赋值,因此,在UseCase的注解处理器分析处理这个类时会使用该元素的默认值。
编写注解处理器
下面是一个简单的注解处理器,我们将用它来读取PassWordUtil类,并使用反射机制查找@UseCase标记。我们会为其提供一组id值,然后它会列出在PassWordUtil类中找到的用例,以及缺失的用例。
package com.rains.annotation.usecase;
import java.util.Collections;
import java.util.List;
import java.lang.reflect.Method;
import java.util.ArrayList;
/**
* Created by Rains on 2016/8/24.
*/
public class UseCaseTracker {
public static void trackUseCase(List<Integer> useCases , Class<?>cl){
for(Method m : cl.getDeclaredMethods()){
UseCase uc = m.getAnnotation(UseCase.class);
if(uc != null){
System.out.println("找到用例" + uc.id() + ":" + uc.description());
useCases.remove(new Integer(uc.id()));
}
}
for(Integer i : useCases){
System.out.println("缺失用例" + i );
}
}
public static void main(String[] args) {
List<Integer> useCases = new ArrayList<>();
Collections.addAll(useCases , 1,2,3,4,5);
trackUseCase(useCases , PasswordUtil.class);
}
}
这个程序用到了两个反射的方法,getDeclaredMethods() 获取类中声明的方法,getAnnotation() 获取方法上声明的指定类型的注解对象。
程序运行结果如下:

网友评论