在JAVA应用中,我们常遇到一些需要使用模版代码的情况。例如,为了编写一个 web service,我们必须提供一对接口和实现作为模版代码。如果使用annotation对远程访问的方法代码进行修饰的话,这个模版就能够使用工具自动生成。 另外,一些API需要使用与程序代码同时维护的附属文件。例如EJB需要一个部署描述符。此时在程序中使用annotation来维护这些附属文件的信息将十分便利而且减少了错误。
1)从Java5.0版发布以来,5.0平台提供了一个正式的annotation功能:允许开发者定义、使用自己的annotation类型。此功能由一个定义annotation类型的语法和一个描述 anntation声明的语法,读取annotation的API,一个使用annotation修饰的class文件 ,一个annotation处理工具(apt)组成。
2)annotation并不直接影响代码语义,但是它能够工作的方式被看作类似程序的工具或者类库,它会反过来对正在运行的程序语义有所影响。annotation可以从源文件、class文件或者以在运行时反射的多种方式被读取。当然annotation在某种程度上使javadoc tag更加完整。一般情况下,如果这个标记对java文档产生影响或者用于生成java文档的话,它应该作为一个javadoc tag;否则将作为一个 annotation。
实例1、Ovrride覆盖父类的方法(如果将父类的方法重写错误,则会出现错误(编译期间检查出错误))。如:由于失误将toString()错写成tostring()时,会出错。应为编译器在父类中没有找到tostring()方法。
package com.langsin.annotation; public class OverrideTest{ // Override的使用 @Override public String toString(){ return "This is override"; } public static void main(String[] args){ OverrideTest test = new OverrideTest(); System.out.println(test.toString()); } }
实例2、Deprecated声明某个方法是过时的,即不再赞成使用。
package com.langsin.annotation; public class DeprecatedTest{ // Deprecated的使用 @Deprecated public void doSomething(){ System.out.println("do something"); } public static void main(String[] args){ DeprecatedTest test = new DeprecatedTest(); test.doSomething(); } } package com.langsin.annotation; public class SubDeprecatedTest extends DeprecatedTest{ @Override public void doSomething(){ System.out.println("do something in sub class"); } public static void main(String[] args){ SubDeprecatedTest sub = new SubDeprecatedTest(); sub.doSomething(); } }
实例3、SuppressWarnings忽略警告,如使用集合类时如果没有使用泛型,就会有类型不安全。可以使用SuppressWanings忽略这些信息,不显示。
package com.langsin.annotation; import java.util.Date; import java.util.Map; import java.util.TreeMap; public class SuppressWarningsTest{ @SuppressWarnings({"unchecked","deprecation"}) public static void main(String[] args){ Map map = new TreeMap(); map.put("hello",new Date()); System.out.println(map.get("hello")); DeprecatedTest test = new DeprecatedTest(); test.doSomething(); } }
标示方法為Deprecated @Deprectated对编译程序说明某个方法已经不建议使用,即该方法是过时的。
java.lang.Deprecated也是個Marker annotation Deprecated这个名称在告知编译程序,被@Deprecated标示的方法是一个不建议被使用的方法抑制编译程序警告@SuppressWarnings 对编译程序说明某个方法中若有警告讯息,则加以抑制
1、定义Marker Annotation,也就是Annotation名称本身即提供信息 对于程序分析工具来说,主要是检查是否有MarkerAnnotation的出现,并作出对应的动作。参见程序范例用@interface建立Annotation
实例1:
public @interface AnnotationTest{ String value();//value属性是默认的 } @AnnotationTest("hello world") public class AnnotationUsage{ public void method(){ System.out.println("usage of annotation"); } public static void main(String[] args){ AnnotationUsage usage = new AnnotationUsage(); usage.method(); } }
注意:如果AnnotationTest中的属性是value则在使用时可以不指定value="",如果不是value属性,则需要指定value***=""。如:
public @interface AnnotationTest{ // String value();//value属性是默认的 String value1(); } @AnnotationTest(value1="hello world") public class AnnotationUsage{ public void method(){ System.out.println("usage of annotation"); } public static void main(String[] args){ AnnotationUsage usage = new AnnotationUsage(); usage.method(); } }
@AnnotationTest({"hello","world"}) = @AnnotationTest(value={"hello","world"})
实例2、设置annotation的默认值,用default
public @interface AnnotationTest{ String[] value() default "hellowrold";//value属性是默认的 } @AnnotationTest //@AnnotationTest("mayparameter ") public class AnnotationUsage{ public void method(){ System.out.println("usage of annotation"); } public static void main(String[] args){ AnnotationUsage usage = new AnnotationUsage(); usage.method(); } }
实例4、枚举用于Annotation
package com.langsin.annotation; public @interface AnnotationTest{ EnumTest value1() default EnumTest.Hello; } enum EnumTest{ Hello, World, Welcome; } package com.langsin.annotation; @AnnotationTest public class AnnotationUsage{ @AnnotationTest public void method(){ System.out.println("usage of annotation"); } public static void main(String[] args){ AnnotationUsage usage = new AnnotationUsage(); usage.method(); } }
1、java.lang.annotation.Retention型态可以在您定义Annotation型态时,指示编译程序该如何对待您的自定义的Annotation型态预设上编译程序会将Annotation信息留在.class档案中,但不被虚拟机读取,而仅用于编译程序或工具程序运行时提供信息
2、在使用Retention型态时,需要提供java.lang.annotation.RetentionPolicy的枚举型态
package java.lang.annotation; public enum RetentionPolicy { SOURCE, //编译程序处理完Annotation信息后就完成任务 CLASS, //编译程序将Annotation储存于class档中,缺省 RUNTIME //编译程序将Annotation储存于class檔中,可由VM读入 }
3、RetentionPolicy为SOURCE的例子是@SuppressWarnings 仅在编译时期告知编译程序来抑制警告,所以不必将这个信息储存于.class档案RetentionPolicy为RUNTIME的时机,可以像是您使用Java设计一个程序代码分析工具,您必须让VM能读出Annotation信息,以便在分析程序时使用搭配反射(Reflection)机制,就可以达到这个目的
4、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接口
5、Annotation下的属性类型必须是:原始类型、一维数组、Class类型、String。实例1、
package com.leangsin.annotation; package java.lang.reflect.Retention; package java.lang.reflect.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotattion{ String hello() default "langsin"; String world(); } package com.langsin.annotation; public class MyTest{ @MyAnnotation(hello="beijin",world="shanghai") public void output(){ System.out.println("output something"); } } package com.langsin.annotation; java.lang.reflect.*; public class MyReflect{ public static void main(String[] args)throws Exception{ Class<MyTest> c = MyTest.class; Method method = c.getMethod("output",Class[]{}); if(method.isAnnotationPresent(MyAnnotation.class)){ MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class); String hello = myAnnotation.hello(); String world = myAnnotation.world(); System.out.println(hello); System.out.println(world); } Annotation[] annotations = method.getAnnotations(); for(Annotation annotation:annotations){ System.out.println(annotation); } } }
注意:使用反射只能取到Retention为RUNTIME和CLASS的注解。
1、使用java.lang.annotation.Target可以定义其使用之时机在定义时要指定java.lang.annotation.ElementType的枚举值之一
package java.lang.annotation; public enum ElementType { TYPE, // 适用class, interface, enum FIELD, // 适用field METHOD, // 适用method PARAMETER, // 适用method上之parameter CONSTRUCTOR, // 适用constructor LOCAL_VARIABLE, // 适用局部变量 ANNOTATION_TYPE, // 适用annotation型态 PACKAGE // 适用package }
实例:
package com.langsin.annotation import java.lang.annotation.*; @Target(ElementType.METHOD) //该Annotation只能放在方法上 public @interface MyTarget{ String value(); } package com.langsin.annotation public class MyTargetTest{ @MyTarget("test") public void test(){ System.out.println("hello world"); } }
注意:在定义Annotation是没有指定Target,则Annotation可以用于类的任何地方
1、想要在使用者制作JavaDoc文件的同时,也一并将Annotation的讯息加入至API文件中使用java.lang.annotation.Documented。实例1:
package com.langsin.annoatation; //注意:加入此注解,导出doc文档是可以出现Annotation @Documented public @interface MyTarget{ String value(); } package com.langsin.annoatation; public class DocumentTest{ public void method(){ System.out.println("hello world"); } }
用javac导出。或者Eclipase中的Projiect——>Generate Javadoc
1、预设上父类别中的Annotation并不会被继承至子类别中。可以在定义Annotation型态时加上java.lang.annotation.Inherited型态的Annotation。实例:
package com.langsin.annotation; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Inherited @Retention(RetentionPolicy.RUNTIME) public @interface InheritedTest { String value(); } package com.langsin.annotation; @Inheritedtest("langsin") //注意只能定义在此处 public class Parent{ public void doSomething(){ Systme.out.println("Hello World"); } } package com.langsin.annotation; public class Child extends Parent{ } package com.langsin.annotation; public class Test{ public static void main(String[] args) { Class<Parent> c = Parent.class; if(c.isAnnotationPresent(InheritedTest.class)){ InheritedTest inheritedTest = c.getAnnotation(InheritedTest.class); String value = inheritedTest.value(); System.out.println(value); } } }