注解(也被称为元数据,描述数据的数据)是在Java SE5中被引入的一项技术,与类、接口、枚举处于同一层次,也将被编译成class文件。
一、注解的作用
1、替代配置文件完成对某些功能的描述,减少程序配置;
2、保持代码清晰易读及编译期类型检查;
3、学习注解方便对开源代码的解读。
二、内置注解
Java SE5内置了以下三种标准注解,定义在java.lang中:
@Override,表示当前方法的定义将覆盖超类中的方法,如果被标记的类并没有实际覆盖超类,则编译器会发出错误警告。
@Deprecated,表示当前方法不应该再使用,当编程人员使用这些被标记的方法时,编译器会发出警告信息。
@SupperessWarnings,表示编译器将忽略特定的警告信息,此注解常用的参数值有:deprecation(忽略使用过时类或者方法),unchecked(忽略执行了未检查装换时警告) , fallthrough(忽略switch直接指向到下一个case块没有break警告),path(忽略类路径,源文件路径中有不存在路径时警告),serial(忽略可序列化类中没有serialVersionUID时的警告),finally(任何finally不能正常执行时的警告),all(以上所有)。
三、元注解
元注解的作用是负责注解其他注解,Java SE5内置了四种元注解:
@Target | 表示该注解可以用于什么地方,可能的ElementType参数包括: CONSTRUCTOR:构造器的声明 FIELD:域声明(包括enum实例) LOCAL_VARIABLE:局部变量声明 METHOD:方法声明 PACKAGE:包声明 PARAMETER:参数声明 TYPE:类、接口(包括注解类型)或enum声明 |
@Retention | 表示需要在什么级别保存该注解信息。可选的RetentionPolicy参数包括: SOURCE:注解存在于源代码中,编译时会被丢弃 CLASS:注解在class文件中可用,但会被VM丢弃 RUNTIME:VM在运行时也将保留注解,因此可以通过反射机制读取注解的信息 |
@Documented | 将此注解包含在Javadoc中 |
@Inherited | 允许子类继承父类中的注解 |
四、自定义注解
下面一段代码摘自于《Java编程思想(第4版)》,描述了注解的定义及使用:
//:annotation/UseCase.javaimport java.lang.annotation.*;//该注解可以作用于方法@Target(ElementType.METHOD)//JVM会读取注解,所以利用反射可以获得注解@Retention(RetentionPolicy.RUNTIME)public @interface UseCase{ //定义成员变量 //成员变量可以通过default指定默认值 //如果成员变量不指定默认值的情况下,在引用接口时则必须给没有默认值的成员变量赋值 public int id(); public String description() default "no description";}//:annotations/PasswordUtils.java //注解的元素在使用时表现为键-值对的形式,其中键为方法名称,值类型为方法返回类型,并且需要置于@UseCase声明之后的括号内 //注解元素可用的类型有:所有基本类型(int,float,boolean等)、String、Class、enum、Annotation、以上类型的数组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(){ return new StringBuilder(password).reverse().toString(); } @UseCase(id=49,description="") public boolean checkForNewPassword(ListprevPasswords,String password){ return !prevPasswords.contains(password); }}
注意:非基本类型的注解元素的值不可为null,这个约束使得处理器很难表现一个元素的存在或缺失的状态,使用空字符串或负数作为默认值是一种常用的做法。
五、注解处理器
如果不能解析注解,那注解也不会比注释更有用。在使用注解的过程中,注解处理器就是用来解析注解的重要工具。下面是一个简单注解处理器,用来读取PasswordUtils类,使用反射机制查找@UseCase标记,列出在PasswordUtils中找到的用例以及缺失的用例。
//: annotations/UseCaseTracker.java //getDeclaredMethods和getAnnotation为反射方法,都属于AnnotatedElement接口(Class、Method和Field都实现了该接口) import java.lang.reflect.*;import java.util.*;public class UseCaseTracker{ public static void trackUseCases(ListuseCases,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())); } } for(int i:useCase){ System.out.println("Warning:Missing use case-"+i); } } public static void main(){ List useCases=new ArrayList (); Collections.addAll(useCase,47,48,49,50); trackUseCases(useCases,PassordUtils.class); } /*Output: Found Use Case:47 Passwords must contain at least one numeric Found Use Case:48 no description Found Use Case:49 New passowords can't equal previously used ones */}