0. Java支持元数据(MetaData), 也就是Annotation(注释), 这种Annotation其实就是代码里的特殊标记, 这些标记可以在编译、类加载、运行时被读取, 并执行相应的处理.
- 元数据 是"描述数据的数据(data about data)".
- Annotation能被用来为程序元素(类、方法、成员变量等)设置元数据.
1. Annotation(既是注释)也是一个接口, 程序可以通过反射来获取指定程序元素的Annotation对象, 然后通过Annotation对象来取得注释里的元数据.
2. 访问和处理Annotation的工具统称APT(Annotation Processing Tool).
3. 使用Annotation时要在其前面增加@符号, 并把该Annotation当成一个修饰符使用, 用于修饰它支持的程序元素. 四个基本Annotation:
- @Override: 强制一个方法必须覆盖父类的方法. (告诉编译器检查这个方法, 确保父类包含一个能被该方法重写的方法, 否则报错. @Override只能用于方法. )
- @Deprecated: 表示某个程序元素(类、方法等)已过时, 使用已过时的程序元素时, 便以其给出警告.
- @SuppressWarnings: 使被修饰的程序元素(以及该程序元素中所有的子元素)取消显示指定的编译器警告. 使用时要在括号里使用name=value形式为该Annotation的成员变量设置值.
import java.util.*; @SuppressWarnings(value="unchecked") public class SuppressWarningsTest { public static void main(String[] args) { List<String> myList = new ArrayList(); } }
- @SafeVarargs: Java7专门为抑制"堆污染(heap pollution)"警告提供的.
4. jDK除了在java.lang下提供了4个基本的Annotation之外, 还在java.lang.annotation包下提供了4个Meta Annotation(元 Annotation), 这四个元Annotation都用于修饰其他的Annotation定义.
- @Retention只能用于修饰一个Annotation定义, 用于指定被修饰的Annotation可以保留多长时间, @Retention包含一个RetentionPolicy类型的value成员变量, 所以使用@Retention时必须为该value成员变量指定值.
value成员变量的值只能是如下三种:
- RetentionPolicy.CLASS: 编译器把Annotation记录在class文件中. 当运行Java程序时, JVM不再保留Annotation. 这是默认值.
- RetentionPolicy.RUNTIME: 编译器把Annotation记录在class文件中. 当运行Java程序时, JVM也会保留Annotation, 程序可以通过反射获取该Annotation信息.
- RetentionPolicy.SOURCE: Annotation只保留在源代码中, 编译器直接丢弃这种Annotation.//定义Testable Annotation保留到运行时 @Retention(value = RetentionPolicy.RUNTIME) public @interface Testable{} //等同于下面这样: @Retention(RetentionPolicy.RUNTIME) //使用Annotation里名为value的成员变量时, 直接在括号里指定value值就行, 不必使用name=value形式. public @interface Testable{}
- @Target也只能修饰一个Annotation定义, 它用于指定被修饰的Annotation能用于修饰哪些程序单元. @Target元Annotation也包含一个名为value的成员变量, 其值可能是如下几种:
- ElementType.ANNOTATION_TYPE: 指定该策略的Annotation只能修饰Annotation.
- ElementType.CONSTRUCTOR: 指定该策略的Annotation只能修饰构造器.
- ElementType.FIELD: 成员变量.
- ElementType.LOCAL_VARIABLE: 局部变量.
- ElementTpye.METHOD: 方法定义.
- ElementType.PACKAGE: 包定义.
- ElementType.PARAMETER: 参数.
- ElementType.TYPE: 指定该策略的Annotation可以修饰类、接口(包括注释类型)或枚举定义. - @Documented用于指定被该元Annotation修饰的Annotation类将被javadoc工具提取成文档, 如果定义Annotation类时使用了@Documented修饰, 则所有使用该Annotation修饰的程序元素的API文档中将或包含该Annotation说明.
- @Inherited 元Annotation指定被他修饰的Annotation将具有继承性(如果某个类使用了@A Annotation(定义该Annotation时使用了@Inherited修饰)修饰, 则其子类将自动被@A 修饰.).
public @interface Test
{}
或者带成员变量的Annotation(成员变量在Annotation中以无形参的方法的形式, 方法名和其返回值定义了该成员变量的名字和类型.):
public @interface MyTag
{
String name();
int age() default 32; // 用default关键字为Annotation的成员变量指定初始值.
}
6. 根据Annotation是否包含成员变量, 将其分两类.
- 标记Annotation: 没有成员变量的Annotation. 这种Annotation利用自身存在与否来提供信息.
- 元数据Annotation: 包含成员变量的Annotation. 因为它们能接受更多的元数据, 所以也被称为元数据Annotation.
7. 使用Annotation的语法类似于修饰符, 可用于类、接口、方法、变量等, 通常放在修饰符之前单独一行. 带有成员变量的Annotation使用时必须制定成员变量的值(或定义时指定初始值(默认值).).
8. 提取Annotation信息. . .. .这章写的真乱.
- 当一个Annotation类型被定义为运行时Annotation后, 该Annotation才会在运行时可见, JVM才会在装在*.class文件时读取保存在class文件中的Annotation.
- java.lang.reflect包下的AnnotatedElement接口代表程序中可以接受注释的程序元素. 其主要实现类:
- Class: 类定义.
- Constructor: 构造器定义.
- Field: 类成员定义.
- Method: 类的方法定义.
- Package: 类的包定义. - 程序通过反射获取某个类的AnnotatedElement对象(如Class、Method等)之后, 就可以通过调用该对象的如下三个方法来访问Annotation信息.
- getAnnotation(Class<T> annotationClass): 返回该程序元素上存在的指定类型的注释, 若不存在, 返回null.
- Annotation[] getAnnotations(): 返回该程序元素上存在的所有注释.
- boolean isAnnotationPresent(Class<? extends Annotation> annotationClass): 判断该程序元素上是否存在指定类型的注释, 存在返true, 木有返false.