Java注解(Annotation)入门

自动JDK5开始,java支持annotation(注解)这一新特性。这个特性给我们开发带来了很多好处。如:JUnit3中的所有测试类必须继承自TestCase来实现,但是在JUnit4中不再继承TestCase而是通过在方法上面添加@Test注解即可,这样就很方便。还有Spring的配置也可以通过注解方式、Hibernate和MyBatis申明数据库表和DTO对象映射关系也可以通过注解来实现。

一、Annotation基础

1、为什么使用Annotation

在JAVA应用中,我们常遇到一些需要使用模版代码的情况。例如,为了编写一个 web service,我们必须提供一对接口和实现作为模版代码。如果使用annotation对远程访问的方法代码进行修饰的话,这个模版就能够使用工具自动生成。 另外,一些API需要使用与程序代码同时维护的附属文件。例如EJB需要一个部署描述符。此时在程序中使用annotation来维护这些附属文件的信息将十分便利而且减少了错误。

2、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 对编译程序说明某个方法中若有警告讯息,则加以抑制

二、自定义Annotation类型

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

三、告知编译程序如何处理@Retention 

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的注解。

四、限定annotation使用对象@Target 

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可以用于类的任何地方

五、要求为API文件@Documented 

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

六、子类是否继承父类@Inherited 

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);  
        }  
    }  
}
少壮不努力,老大徒悲伤。——汉乐府古辞《长歌行》
0 不喜欢
说说我的看法 -
全部评论(
没有评论
关于
本网站属于个人的非赢利性网站,转载的文章遵循原作者的版权声明,如果原文没有版权声明,请来信告知:hxstrive@outlook.com
公众号