目录
Java编程思想(一)第1~4章:概述
Java编程思想(二)第5章:初始化和清理
Java编程思想(三)第6章:访问权限
Java编程思想(四)第7章:复用类
Java编程思想(五)第8章:多态
Java编程思想(六)第9章:接口
Java编程思想(七)第10章:内部类
Java编程思想(八)第11章:持有对象
Java编程思想(九)第12章:异常
Java编程思想(十)第13章:字符串
Java编程思想(十一)第14章:类型信息
Java编程思想(十二)第15章:泛型
Java编程思想(十三)第16章:数组
Java编程思想(十四)第17章:深入研究容器
Java编程思想(十五)第18章:Java I/O系统
Java编程思想(十六)第19章:枚举
Java编程思想(十七)第20章:注解
Java编程思想(十八)第21章:并发
第二十章、注解
目录
1. 基本语法
1.1 定义注解
1.2 元注解
2. 编写注解处理器
2.1 Annotation注解元素
2.2 默认值限制
2.3 生成外部文件
2.4 注解不支持继承
3 使用apt处理注解
4. 将观察者模式用于apt
5. 基于注解的单元测试
前言
JDK内置的3中Annotation
在JDK5中,内置了3个通用目的的注解Annotation,这三个内置的注解在java.lang包下:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test{}
Java只内置三个标准注解(如上所述),和下列4个元注解:
@Target注解
用于指示注解所应用的目标程序元素种类,该注解常和ElementType枚举类型一起联合使用,ElementType枚举提供了java程序中声明的元素类型如下:
@Retention注解
该注解用于指示所定义的注解类型的注释在程序声明周期中得保留范围,该注解常和RetentionPolicy枚举联合使用。RetentionPolicy枚举常量定义了注解在代码中的保留策略
@Documented
将此注解包含在Javadoc中
@Inherited
允许子类继承父类中的注解
使用注解的时候,很重要的一部分就是创建&使用注解处理器。Java提供了一个外部工具apt用来解析带有注解的Java源代码包。
正常使用注解时,需要在注解中定义元素,用于接收程序设置的值,正常定义注解的例子如下:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UseCase{
public int id();
public String description() default “no description”; //可以定义属性默认值
}
正常定义注解Annotation的方式类似定义接口,id和description是注解UseCase的属性,而不是方法,注解中不能定义方法只能定义属性。其中description属性有默认的值“no description“,即在使用时如果没有指定description的值,则程序使用其默认值。
上面UseCase注解用于跟踪方法的测试用例说明,使用上面注解的例子如下:
public class PasswordUtils{
@UseCase(id = 47, description = “Passwords must contain at least one numeric”)
public Boolean validatePassword(String password){
return (password.mathes(“\\w*\\d\\w*”));
}
@UseCase(id = 48)
public String encryptPassword(Srring password){
return new StringBuilder(password).reverse().toString();
}
@UseCase(id = 49, description = “New passwords can’t equal previously used ones”)
public Boolean checkForNewPassword(List prevPasswords, String password){
return !prevPasswords.contains(password);
}
}
JDK5中提供了Annotation相关的API,结合使用java的反射机制可以实现自定义的Annotation注解处理器(JDK中也提供了使用APT,Annotationprocess tool方式处理注解,在后面会讲解),处理上述Annotation的例子如下:
public class UseCaseTracker{
public static void traceUseCases(List
//获取指定类中所有声明的方法
for(Method m : clazz.getDeclaredMethods()){
//获取方法上指定类型的注解
public class UseCaseTracker{
public static void traceUseCases(List useCases, Class> clazz){
//获取指定类中所有声明的方法
for(Method m : clazz.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 : useCases){
System.out.println(“Warning: Missing use case-” + i);
}
}
public static void main(String[] args){
List useCases = new ArrayLis();
Collections.addAll(useCases, 47, 48, 49, 50);
trackUseCases(useCases, PasswordUtils.class);
}
}
这个程序用到了两个反射的方法:getDeclaredMethods()和m.getAnnotation(UseCase.class):
Annotation注解中的元素只能是下面的数据类型:
除了上面这些类型以外,如果在注解中定义其他类型的数据,编译器将会报错。
注意:注解中的元素要么指定默认值,要么由使用的类赋值,如果即没有默认值,使用类也没有赋值的话,注解元素是不会像普通类成员变量一样给定默认值,即必须赋值或者显示指定默认值。默认值例子如下:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DefaultValue{
public int id() default -1;
public String description() default “”;
}
Enterprise JavaBean这样的技术,每一个Bean都需要大量的接口和部署来描述文件,这些都属于样板文件。然而,如果我们使用注解的话,可以将所有信息都保存在javaBean中的源文件中。为此,我们需要一些新的注解,用以定义与Bean相连的数据库表的名字,以及与Bean属性管理的列的名字和SQL类型。
@Target(ElementType.TYPE)//该注解只能应用在类上
@Retention(RetentionPolicy.RUNTIME)
public @interface DBTable{//指定数据库名称
public String name() default “”;
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Constraints{//数据库约束
boolean primaryKey() default false;
boolean allowNull() default true;
boolean unique() default false;
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLString{//String类型数据
int value() default 0;
String name() default “”;
Constraints constraints() default @Constraints;//注解的属性元素也是注解
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLInteger{//int类型数据
String name() default “”;
Constraints constraints() default @Constraints;
}
不能使用关键字extends 来继承某个@interface
5.1 将@Unit用于泛型
5.2 不需要任何“套件”
5.3 实现@Unit
5.4 移除测试代码
添加@Test注解,并使用Javassist工具类库将字节码工程,删除所有的@Test注解。(??)