Annotation
在JAVA应用中,我们常遇到一些需要使用模版代码的情况。
另外,一些API需要使用与程序代码同时维护的附属文件。
Annotation工作方式
从Java5.0版发布以来,5.0平台提供了一个正式的annotation功能:
annotation并不直接影响代码语义,但是它能够工作的方式被看作类似程序的工具或者类库,它会反过来对正在运行的程序语义有所影响。
当然annotation在某种程度上使javadoc tag更加完整。
java.lang.Override是个Marker annotation
用于标示的Annotation,Annotation名称本身即表示了要给工具程序的信息。(和Serializable一样只是个信息)
public class OverrideTest {
@Override//强制保证子类的某个方法确实覆盖了父类的某个方法,编译时会检查,可以防止出错
public String toString(){
return "This is override!";
}
public static void main(String[] args){
OverrideTest test=new OverrideTest();
System.out.println(test.toString());
}
}
java.lang.Deprecated也是个Marker annotation
Deprecated这个名称在告知编译程序,被@Deprecated标示的方法是一个不建议被使用的方法。
public class DeprecatedTest {
@Deprecated//告诉用新户此方法可能会出问题,不建议使用,不删除是为了以前调用了这个方法的可以使用
public void doSomething(){
System.out.println("do something");
}
public static void main(String[] args){
DeprecatedTest test=new DeprecatedTest();
test.doSomething();
}
}
public class OverrideTest {
@Override//强制保证子类的某个方法确实覆盖了父类的某个方法,编译时会检查,可以防止出错
public String toString(){
return "This is override!";
}
public static void main(String[] args){
OverrideTest test=new OverrideTest();
System.out.println(test.toString());
}
}
抑制编译程序警告@SuppressWarnings
对编译程序说明某个方法中若有警告讯息,则加以抑制
public class SuppressWarningsTest {
@SuppressWarnings({"unchecked","deprecation"})//压制警告,并指定警告类型,实际上是一个数组,没用的或重名的会自动忽略
public static void main(String[] args){
// Map<String,Date> map=new TreeMap<String,Date>();
Map map=new TreeMap();
map.put("Hello", new Date());
System.out.println(map.get("hello"));
DeprecatedTest test=new DeprecatedTest();
test.doSomething();
}
}
public @interface AnnotationTest {
// String value() default "langsin";
//定义一个名为value的变量,这是Annotation变量的定义方式,缺省值为"langsin"
enumTest value1() default enumTest.Hello;
// 定义类型为8种原生类型,字符串类型,枚举类型,一维数组类型,Class类类型,Annotation类型。
}
enum enumTest {
Hello, World, Welcome
};
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
public class MyReflection {
public static void main(String[] args)throws Exception{
MyTest myTest=new MyTest();
Class<MyTest> c=MyTest.class;
Method method=c.getMethod("output", new Class[]{});
// 判断某个Annotation是否存在
if(method.isAnnotationPresent(MyAnnotation.class)){
method.invoke(myTest,new Object[]{});
// 获得Annotation,返回一个MyAnnotation
MyAnnotation myAnnotation=method.getAnnotation(MyAnnotation.class);
String hello=myAnnotation.hello();//定义时当作一个变量,取值时当作一个方法
String world=myAnnotation.world();
System.out.println(hello);
System.out.println(world);
}
// getAnnotation返回当前元素存在的所有注解,获得method方法前面的所有注解
Annotation[] annotations=method.getAnnotations();
for(Annotation annotation : annotations){
// annotationType()获得当前Annotation对应的Class类型,getName()返回当前Annotation名的全称
System.out.println(annotation.annotationType().getName());
}
}
}
java.lang.annotation.Retention型态可以在您定义Annotation型态时,
指示编译程序该如何对待您的自定义的Annotation型态
预设上编译程序会将Annotation信息留在.class档案中,但不被虚拟机读
取,而仅用于编译程序或工具程序运行时提供信息
在使用Retention型态时,需要提供
java.lang.annotation.RetentionPolicy的枚举型态
public enum RententionPolicy{
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信息
public @interface MyAnnotation {
String hello() default "langsin";
String world();
}
@MyTarget(value = "xyz")
public void doSomething(){
System.out.println("hello world");
}
}
public @interface DocumentedAnnotation {
String hello();
}
/**
* This is the comments that I have added
*/
@DocumentedAnnotation(hello = "welcome")
public void method(){
System.out.println("hello world");
}
}
@Retention(RetentionPolicy.RUNTIME)
public @interface InheritedTest {
String value();
}
public class Parent {
public void doSomething(){
System.out.println("hello");
}
}
public void doSomething(){
}
}
public static void main(String[] args){
Class<Child> c=Child.class;
// Class<Parent> c=Parent.class;
if(c.isAnnotationPresent(InheritedTest.class)){
InheritedTest inheritedTest=(InheritedTest) c.getAnnotation(InheritedTest.class);
String value=inheritedTest.value();
System.out.println(value);
}
}
}