JavaAnnotation,枚举与反射的使用
Annotation的由来:
在JAVA应用中,我们常遇到一些需要使用模板代码的情况,例如,为了编写一个web service,我们必须提供一对接口和实现作为模板代码。如果使用annotation对远程访问代码进行修饰的话,这个模板就能够使用工具自动生成。
另外,一些API需要使用与程序代码同时维护的附属文件,例如EJB需要一个部署描述符,此时在程序中使用annotation来维护这些附属文件的信息将十分便利而且减少了错误。
从Java5.0版本发布以来,5.0平台提供了一个正式的annotation功能:允许开发者定义、使用自己的annotation类型。此功能由一个定义annotation类型的语法和一个描述annotation声明的语法,读取annotation的API,一个使用annotation修饰的class文件,一个annotation处理工具(apt)组成。
annotation并不直接影响代码的语义,但是它能够工作的方式被看做类似程序的工具或者类库,它会反过来对正在运行的程序语义有所影响。annotation可以从源文件,class文件或者以运行时反射的多种方式被读取。
当然annotation在某种程度上使javadoc tag更加完整,一般情况下,如果这个标记对java文档产生影响或者用于生成java文档的话,它应该作为一个javadoc tag;否则将作为一个annotation.
使用JDK5.0内建的Annotation
@Override @Deprecated @SuppressWarnings
java.lang.Override是个Marker annotation是用于标示的Annotation,Annotation名称本身即表示了要给工具程序的信息。
对编译程序说明某个方法已经不建议使用,即该方法是过时的。java.lang.Depreacted也是个Marker annotation.
Deprecate这个名称告知编译程序,被Deprecated指示的方法是一个不建议使用的方法。
@SuppressWarnings
对编译程序说明某个方法中若有警告讯息,则加以抑制。
自定义Annotation
定义Marker Annotation,也就是Annotation名称本身提供信息,对于程序分析工具来说,主要是检查是否有Marker Annotation的出现,并作出对应的动作。
value成员设定默认值,用“default”关键字
数组方式的使用, 枚举在Annotation中的应用。
使用@interface 自行定义Annotation形态时,实际上是自动继承了java.lang.annotation.Annotation接口
由编译程序自动为您完成其它产生的细节,在定义Annotation形态是,不能继承其它的Annotation形态或是接口。
定义Annotation形态时也可以使用包来管理类别方式类同于类的导入功能。
告知编译程序如何处理@Retention
java.lang.annotation.Retention形态可以在您定义Annotation形态时,指示编译程序该如何对待您的自定义的Annotation形态预设上编译程序会将Annotation信息留在.class档案中,但不能被虚拟机读取,而仅用于编译程序或工具程序运行时提供信息。
在使用Retention形态时,需要提供java.lang.annotation.RetentionPolicy的枚举形态
package java.lang.annotation;
public enum RetentionPolicy {
SOURCE, //编译程序处理完Annotation信息后就完成任务
CLASS,//编译程序将Annotation存储于class档中,缺省
RUNTIME // 编译程序将Annotation存储于class档中,可由VM读入
}
RetentionPolicy为SOURCE的例子是@SuppressWarnings
仅在编译时期告知编译程序来抑制警告,所以不必将这个信息存储于.class档案。
RetentionPolicy为RUNTIME的时机,可以像是您使用Java设计一个程序代码分析工具,您必须让VM能读出Annotation信息,以便在分析程序时使用。
搭配反射(Reflection)机制,就可以达到这个目的。
java.lang.reflect.AnnotatedElement接口
public Annotation getAnnotation(Class annotationType);
public Annotation[] getAnnotations();
public Annotation[] getDeclaredAnnotations();
public boolean isAnnotationPresent(Class annotationType);
Class, Constructor, Field, Method, Package等类别,都实现了AnnotatedElement接口。
定义Annotation时,必须设置RetentionPolicy为RUNTIME, 也就是可以在VM中读取Annotation信息。
package com.test.factory;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String hello() default "linxin";
String world();
}
package com.test.factory;
public class MyTest {
@MyAnnotation(hello="beijing", world="tai")
public void output() {
System.out.println("MyTest");
}
}
package com.test.factory;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
public class MyReflectionTest {
public static void main(String[] args) throws Exception {
Class<MyTest> c = MyTest.class;
Method method = c.getMethod("output", new Class[]{});
if (method.isAnnotationPresent(MyAnnotation.class)) {
MyAnnotation a = method.getAnnotation(MyAnnotation.class);
System.out.println(a.hello());
System.out.println(a.world());
method.invoke(c.newInstance(), new Class[]{});
}
Annotation[] a = method.getAnnotations();
for (Annotation b : a) {
System.out.println(b.annotationType().getName());
}
}
}
限定annotation使用对象@Target
使用java.lang.annotation.Target可以定义其使用之时机
在定义时要指定java.lang.annotation.ElementType的枚举值之一。
想要在使用制作JavaDoc文件的同时,也一并将Annotation的讯息加入至API文件中。
预设上父类别中的Annotation并不会被继承至子类别中
可以在定义Annotation形态时加上
java.lang.annotation.Inherited形态的Annotation
事实上Inherited在JDK1.5中没有发生作用。
Java枚举:
package lyb;
public class Enumeration1 {
// 私有的构造方法
private Enumeration1() {}
public static final Enumeration1 SUN
= new Enumeration1() {
@Override
public Enumeration1 nextDay() {
return SAT;
}
} ;
public static final Enumeration1 SAT
= new Enumeration1() {
@Override
public Enumeration1 nextDay() {
return SUN;
}
};
public Enumeration1 nextDay() {
/*if (this == Enumeration1.SAT) {
return Enumeration1.SUN;
} else {
return Enumeration1.SAT;
}*/
return null;
}
@Override
public String toString() {
return (this == Enumeration1.SAT) ? "SAT" : "SUN";
}
}
package lyb;
import java.util.Date;
public class TestEnum {
public static void main(String[] args) {
Enumeration1 e = Enumeration1.SAT;
System.out.println(e.nextDay());
Enumeration2 e2 = Enumeration2.MON;
System.out.println(e2);
System.out.println(Enumeration2.valueOf("MON"));
Enumeration2[] es = Enumeration2.values();
for (Enumeration2 enumeration2 : es) {
System.out.println(enumeration2);
}
System.out.println(e2.name());
System.out.println(e2.ordinal());
System.out.println(es.length);
new Date(300) {
};
new Runnable() {
public void run() {
// TODO Auto-generated method stub
}
};
}
public enum Enumeration2 {
// 注意此处时子类实例化
MON{
}, TUES(), WED, THUR, FRI, SAT, SUN;
private Enumeration2() {
System.out.println("first");
}
private Enumeration2(int i) {
System.out.println("second");
}
}
}