1. 元注解 (meta-annotation)
在Java 1.5以后,jdk提供了三个标准注解,定义在java.lang中:
@Override: 用于修饰此方法覆盖了父类的方法
@Deprecated: 用于修饰已经过时的方法
@SuppressWarnnings: 用于通知java编译器禁止特定的编译警告
而元注解的作用,就是负责注解其他注解的,包括上面三个java自带的注解,也包括用户自定义的注解类型。Java 1.5中有4个标准的元注解,被用来提供对其它Annotation类型作说明:
@Target
@Targer说明了注解所修饰的对象范围,即被描述的注解可以用在什么地方,取值有:
使用实例:
@Target(ElementType.TYPE)
public @interface Table {
/**
* 数据表名称注解,默认值为类名称
* @return
*/
public String tableName() default "className";
}
@Target(ElementType.FIELD)
public @interface NoDBColumn {
}
@Retention
@Retention定义了该注解被保留的时间长短,即表示被描述的注解在什么范围内有效,用于描述注解的生命周期。取值有:
实例如下:
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
public String name() default "fieldName";
public String setFuncName() default "setField";
public String getFuncName() default "getField";
public boolean defaultDBValue() default false;
}
2. 自定义注解
使用@interface自定义注解时,自动实现了java.lang.annotation.Annotation接口,由编译器自动完成其他细节。在定义注解时,不能继承其他注解或接口。在注解定义体中,每一个方法实际上是声明了一个配置参数,方法名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是Class、String、enum、基本类型),可以通过default来声明参数的默认值。
如果只有一个参数成员,最好把参数名设为value。
实例如下:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 水果名称注解
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FruitName {
String value() default "";
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 水果颜色注解
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FruitColor {
/**
* 水果颜色枚举
*/
public enum Color {
BLUE, RED, GREEN
};
/**
* 颜色属性
*/
Color fruitColor() default Color.GREEN;
}
public class Apple {
@FruitName("Apple")
private String appleName;
@FruitColor(fruitColor = Color.RED)
private String appleColor;
@FruitProvider(id = 1, name = "北京平谷大桃集团", address = "北京市平谷区")
private String appleProvider;
//省略setter和getter方法
}
注解元素必须有确定的值,要么在定义注解的默认值中指定,要么在使用注解时指定,非基本类型的注解元素的值不可为null,因此,使用空字符串或者0或者-1作为默认值是一种常用的做法。
/**
* 水果供应商注解
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FruitProvider {
/**
* 供应商编号
*/
public int id() default -1;
/**
* 供应商名称
*/
public String name() default "";
/**
* 供应商地址
*/
public String address() default "";
}
3. 注解处理器
如果没有用来读取注解的方法,那么注解也就没什么用了。使用注解的过程中,很重要的一部分就是创建和使用注解处理器。Java 1.5扩展了反射机制的API,以帮助程序员快速的构造自定义注解处理器。
注解处理器类库java.lang.reflect.AnnotatedElement,这是一个接口,它的实现类有AccessibleObject, Class, Constructor, Field, Method, Package,所以程序通过反射获取了某个类的AnnotatedElement对象以后,程序就可以通过调用该对象以下四个方法来方位Annotation信息:
一个简单的注解处理器:
public class FruitInfoUtil {
public static void getFruitInfo(Class> clazz) {
String strFruitName = "水果名称:";
String strFruitColor = "水果颜色:";
String strFruitProvider = "供应商信息:";
Field[] fields = clazz.getDeclaredFields();
//遍历fields
for (Field field : fields) {
if (field.isAnnotationPresent(FruitName.class)) {//如果有FruitName注解
//获取注解
FruitName fruitName = field.getAnnotation(FruitName.class);
//拿到注解的值并打印
strFruitName += fruitName.value();
System.out.println(strFruitName);
} else if (field.isAnnotationPresent(FruitColor.class)) {//如果有FruitColor注解
FruitColor fruitColor = field.getAnnotation(FruitColor.class);
strFruitColor += fruitColor.fruitColor().toString();
System.out.println(strFruitColor);
} else if (field.isAnnotationPresent(FruitProvider.class)) {//如果有FruitProvider注解
FruitProvider fruitProvider = field.getAnnotation(FruitProvider.class);
strFruitProvider += "供应商编号:" + fruitProvider.id() + " 供应商名称:"
+ fruitProvider.name() + " 供应商地址:" + fruitProvider.address();
System.out.println(strFruitProvider);
}
}
}
}
public class FruitRun {
public static void main(String[] args) {
FruitInfoUtil.getFruitInfo(Apple.class);
}
}
水果名称:Apple
水果颜色:RED
供应商信息:供应商编号:1 供应商名称:北京平谷大桃集团 供应商地址:北京市平谷区