认识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<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() 获取方法上声明的指定类型的注解对象。

程序运行结果如下:

result.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,288评论 19 139
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 174,827评论 25 709
  • 1. 简介 1.1 什么是 MyBatis ? MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的...
    笨鸟慢飞阅读 5,872评论 0 4
  • 上边一个“田”字,下边一个“比”字,你知道念啥吗?在法源寺的一个殿堂前挂着一块匾,上书第一个字便是田比的上下结构,...
    老栾乱弹阅读 1,179评论 0 0
  • 没有电子产品的时代,热衷于面对面的交谈。有了电子产品的时代,即使见了面也低头刷屏。没经历过大吃大喝畅谈,也没...
    溜达杨阅读 286评论 0 0