在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);
}
}
}