认识Java注解

什么是注解?

注解(也被称为元数据)为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便地使用这些数据。


注解定义

@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 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 useCases , Classcl){        
        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 useCases = new ArrayList<>();        
      Collections.addAll(useCases , 1,2,3,4,5);        
      trackUseCase(useCases , PasswordUtil.class);   
  }
}

这个程序用到了两个反射的方法,getDeclaredMethods() 获取类中声明的方法,getAnnotation() 获取方法上声明的指定类型的注解对象。

程序运行结果如下:

result.png

你可能感兴趣的:(认识Java注解)