在Java中,Annotation(注解)是JDK5.0及以后版本引入的,它是一种可以添加到Java源
代码中的元数据(用来描述数据的数据)语法形式。类,方法,变量,参数和包都可以用于注解。
元数据的作用,大致可分为三类:
编写文档:通过代码里标识的元数据生成文档。
代码分析:通过代码里标识的元数据对代码进行分析。
编译检查:通过代码里标识的元数据让编译器能实现基本的编译检查。
Java定义了一个内置的注解集。
应用于Java代码中的注解:
@Override –校验方法是重写方法。如果方法在父类中未找到会产生一个编译警告。@Deprecated –标记方法已经废弃不用了。如果还在使用此方法会产生一个编译警告。@SuppressWarnings –告知编译器抑制由注解参数指定的编译时期警告。
应用于其它注解的注解:
@Retention –用来声明注解的保留策略,有CLASS、RUNTIME和SOURCE这三种,分别表示注解保存在类文件、JVM运行时刻和源代码中。只有当声明为RUNTIME的时候,才能够在运行时刻通过反射API来获取到注解的信息。如果注解声明中不存在Retention注解,则保留策略默认为RetentionPolicy.CLASS。
@Documented--指示某一类型的注解将通过javadoc和类似的默认工具进行文档化。@Target--指示注解类型所适用的程序元素的种类。如果注解类型声明中不存在Target
元注解,则声明的类型可以用在任一程序元素上。
@Inherited -指示注解类型被自动继承。
Java允许自定义的注解。注解通过在类名前使用@interface注解来定义。通过@ Retention 注解可以指定在运行时是否保留该注解。@Target 让你定义这个注解可以在哪个程序元素上使用,例如:类,字段,方法等。
以下是一个标准的注解定义:
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface MyAnnotation { public String name(); public int value() default 0; }
其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型。可以通过default来声明参数的默认值。
在程序中添加的注解,可以在编译时刻或是运行时刻通过注解处理器来进行处理,注解处理器的本质是通过Java反射来处理。
替换.properties和xml配置文件:注解可以为作为软件和部署的一部分的配置信息提供一种简单和易于理解的方式。然而,当配置信息需要在运行时动态改变时,注解就不适合了。
支持横切关注点:注解是一种面向方面,但实际上很少处理方面的方式。注解能够很好的处理像依赖注入、服务发现管理对象、验证和许多其他类似的事情。只要需要用到面向方面编程,你又不想另外使用一种面向方面语言如AspectJ,这时注解是一个可行的选择。
本示例通过一个完整的例子自定义一个注解并使用Java反射来解析注解。
(1) 定义注解ContactValidator:
packagecom.jackie.codeproject.annotation; import java.lang.annotation.Documented; importjava.lang.annotation.ElementType; importjava.lang.annotation.Retention; importjava.lang.annotation.RetentionPolicy; importjava.lang.annotation.Target; /** * 联系方式校验 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) @Documented public@interfaceContactValidator { public ContactType type(); }(2)定义联系方式类型枚举ContactType:
packagecom.jackie.codeproject.annotation; /** * 联系方式类型 */ publicenum ContactType { EMAIL,PHONE,MOBILE,WEBSITE }
(3) 校验工具类ValidatorUtil:
packagecom.jackie.codeproject.annotation; importjava.util.regex.Matcher; importjava.util.regex.Pattern; publicclass ValidatorUtil { /** * 校验邮箱 * * @param email * @return */ publicstaticbooleanisValidEmail(String email) { Pattern p =Pattern.compile(".+@.+\\.[a-z]+"); Matcher m =p.matcher(email); return m.matches(); } /** * 校验电话 * * @param phone * @return */ publicstaticbooleanisValidPhone(String phone) { Pattern p =Pattern.compile("\\d\\d([,\\s])?\\d\\d\\d\\d([,\\s])?\\d\\d\\d\\d"); Matcher m =p.matcher(phone); return m.matches(); } /** * 校验手机号 * * @param mobile * @return */ publicstaticbooleanisValidMobile(String mobile) { Pattern p =Pattern.compile("\\d\\d(\\d[,\\s])?\\d\\d\\d([,\\s])?\\d\\d\\d\\d"); Matcher m =p.matcher(mobile); return m.matches(); } /** * 校验网址 * * @paramwebsite * @return */ publicstaticbooleanisValidWebsite(Stringwebsite){ Pattern p =Pattern.compile("^(https?|ftp|file)://.+$"); Matcher m =p.matcher(website); return m.matches(); } }
(4) 用户类User:
packagecom.jackie.codeproject.annotation; publicclass User { /** * 姓名 */ private Stringname; /** * 邮箱 */ @ContactValidator(type = ContactType.EMAIL) private Stringemail; /** * 电话 */ @ContactValidator(type = ContactType.PHONE) private Stringphone; /** * 手机号 */ @ContactValidator(type = ContactType.MOBILE) private Stringmobile; /** * 网址 */ @ContactValidator(type = ContactType.WEBSITE) private Stringwebsite; public String getName() { returnname; } publicvoid setName(String name) { this.name = name; } public String getEmail() { returnemail; } publicvoid setEmail(String email) { this.email = email; } public String getPhone() { returnphone; } publicvoid setPhone(String phone) { this.phone = phone; } public String getMobile() { returnmobile; } publicvoid setMobile(String mobile) { this.mobile = mobile; } public String getWebsite() { returnwebsite; } publicvoid setWebsite(String website) { this.website = website; } }
(5) 注解解析器FieldAnnotationParser:
packagecom.jackie.codeproject.annotation; importjava.lang.annotation.Annotation; importjava.lang.reflect.Field; importjava.lang.reflect.Modifier; publicclass FieldAnnotationParser { /** * 注解解析器 * @paramuser * @throws IllegalArgumentException * @throws IllegalAccessException */ publicstaticvoidparser(Useruser)throws IllegalArgumentException, IllegalAccessException { //获取所有字段 Field[]fields = user.getClass().getDeclaredFields(); for (Field field : fields) { //获取字段上的所有注解 Annotation[] annotations = field.getAnnotations(); for (Annotation annotation : annotations) { //如果是ContactValidator注解 if (annotationinstanceofContactValidator) { ContactValidator contactValidator = (ContactValidator) annotation; //如果是私有字段,设置反射的对象在使用时取消 Java语言访问检查 if (field.getModifiers() == Modifier.PRIVATE) { field.setAccessible(true); } boolean result =false; //获取字段值 String fieldValue = (String) field.get(user); switch (contactValidator.type()) { caseEMAIL: result =ValidatorUtil.isValidEmail(fieldValue); break; casePHONE: result =ValidatorUtil.isValidPhone(fieldValue); break; caseMOBILE: result =ValidatorUtil.isValidMobile(fieldValue); break; caseWEBSITE: result =ValidatorUtil.isValidWebsite(fieldValue); break; } if(!result){ System.out.println("Invalid " + field.getName() + ": " +fieldValue); } } } } } }
(6) 测试类AnnotationTest:
packagecom.jackie.codeproject.annotation; publicclass AnnotationTest { /** *主函数 * @param args * @throws IllegalAccessException * @throws IllegalArgumentException */ publicstaticvoidmain(String[] args)throws IllegalArgumentException,IllegalAccessException { User user =new User(); user.setName("TimSturt"); user.setPhone("0931234 3819"); //错误的电话格式 XXX XXXX XXXX user.setMobile("023912 9123"); //正确的手机格式XXXXXX XXXX user.setEmail("[email protected]"); //正确邮箱格式 user.setWebsite("fttp://test.com"); //错误的网站url FieldAnnotationParser.parser(user); } }
运行结果如下:
Invalid phone: 093 1234 3819
Invalid website: fttp://test.com
注:示例代码主要是参考http://royjin.wordpress.com/2010/06/30/java-annotation-practical-tutorials/这篇文章,感觉例子不错,本人稍微做了修改。如果想更多的了解Java反射知识,可以参见我的另一篇blog"Java反射"。