zoukankan      html  css  js  c++  java
  • metaannotation

    转自:http://xyiyy.javaeye.com/blog/362575 

    1. 所谓meta-annotation就是Annotation类型的数据,也就是Annotation类型的Annotation,在定义Annotation类型时,为Annotation类型加上Annotation可以为处理Annotation类型的分析工具提供更多的信息。

    2. java.lang.annotation.Retention类型可以在您定义Annotation类型时,指示编译器该如何对待自定义的Annotation类型,编译器默认会将Annotation信息留在.class文件中,但不被JVM读取,而仅用于编译器或工具程序运行时提供信息。

    3. 在使用Retention类型时,需要提供java.lang.annotation.RetentionPolicy的枚举类型。RetentionPolicy的枚举类型定义如下所示:

    Java代码 复制代码
    1. package java.lang.annotation;   
    2. public enum RetentionPolicy   
    3. {   
    4.     SOURCE, //编译器处理完Annotation信息后就没事了   
    5.    CLASS,   //编译器将Annotation存储于class文件中,默认   
    6.    RUNTIME,  //编译器将Annotation存储于class文件中,可由VM读入   
    7. }  
          RetentionPolicy为SOURCE的例子是@SuppressWarning,这个信息的作用仅在编译时期告知编译器来抑制,所以不必将这个信息存储于.class文件中。

          RetentionPolicy为RUNTIME的时机,可以像是您使用Java设计一个程序代码分析工具,您必须让VM能读出Annotation信息,以便在分析程序时使用,搭配反射机制,就可以达到这个目的。

          J2SE 5.0新增了java.lang.reflect.AnnotatedElement接口,其中定义有4个方法:

    Java代码 复制代码
    1. public Annotation getAnnotation(Class annotationType);   
    2. public Annotation[] getAnnotations();   
    3. public Annotation[] getDeclaredAnnotations();   
    4. public boolean isAnnotationPresent(Class annotationType);  

          Class,Field,Method,Package,Constructor等类,都实现了AnnotatedElement接口,所以可以从这些类实例上,分别取得标示于其上的Annotation与相关信息。由于是在执行时期读取Annotation信息,所以定义Annotation时必须设定RententionPolicy为RUNTIME,也就是可以在VM中读取Annotation信息。举例来说,假设设计了一个如下的Annotation。

    Java代码 复制代码
    1. package ysu.hxy;   
    2.   
    3. import java.lang.annotation.Retention;   
    4. import java.lang.annotaion.RetentionPolicy;   
    5.   
    6. @Retention(RetentionPolicy.RUNTIME)   
    7. public @interface someAnnotation   
    8. {   
    9.     String value();   
    10.     String name();   
    11. }  

     由于RetentionPolicy为RUNTIME,编译器在处理SomeAnnotation时,会将Annotation及给定的相关信息编译至.class文件中,并设定为VM可以读出Annotation信息。接着可以使用如下范例来使用我们刚才定义的SomeAnnotaion。    

    Java代码 复制代码
    1. package ysu.hxy;   
    2.   
    3. public class SomeClass3   
    4. {   
    5.     @SomeAnnotation(   
    6.         value = "annotation value1",   
    7.         name = "annotation name1"  
    8.     )   
    9.        
    10.     public void doSomething()   
    11.     {   
    12.         //...   
    13.     }   
    14. }  

     现在假设要设计一个源代码分析工具来分析所设计的类,一些分析时所需的信息已经使用Annotation标示于类中了,可以在执行时读取这些Annotation的相关信息。下面是个简单的范例:

    Java代码 复制代码
    1. package ysu.hxy;   
    2.   
    3. import java.lang.annotation.Annotation;   
    4. import java.lang.reflect.Method;   
    5.   
    6. public class AnalysisApp   
    7. {   
    8.     public static void main(String[] args) throws NoSuchMethodException    
    9.     {   
    10.         Class<SomeClass3> c= SomeClass3.class;   
    11.   
    12.         // 因为SomeAnnotation标示于doSomething()方法上   
    13.         //所以要取得doSomething()方法的Method实例    
    14.         Method method = c.getMethod("doSomething");   
    15.   
    16.         //如果SomeAnnotation存在   
    17.         if(method.isAnnotationPresent(SomeAnnotation.class))   
    18.         {   
    19.             System.out.println("找到@Annotation");   
    20.             //取得Annotation   
    21.             SomeAnnotation annotation =    
    22.                  method.getAnnotation(SomeAnnotation.class);   
    23.             //取得value成员值   
    24.             System.out.println("\tvalue = " + annotation.value());   
    25.             //取得name成员值   
    26.             System.out.println("\tname = " + annotation.name());   
    27.         }   
    28.         else  
    29.         {   
    30.             System.out.println("没有找到@SomeAnnotation");   
    31.         }   
    32.   
    33.         //取得doSomething()方法上所有的Annotation    
    34.         Annotation[] annotations = method.getAnnotations();   
    35.         //显示Annotation名称    
    36.         for(Annotation annotation : annotations)   
    37.         {   
    38.             System.out.println("Annotation名称:"+ annotation.annotationType().getName());   
    39.         }   
    40.     }   
    41. }  

     若Annotation标示于方法上,就要取得方法的Method代表实例。同样地如果Annotation标示于类或包上,就要分别取得类的Class代表实例或者包的Package代表实例。之后可以使用实例上的getAnnotation()等相关方法,以测试是否可取得Annotation或进行其他操作。此示例的执行结果如下:

    D:\hxy>java ysu.hxy.AnalysisApp
    找到@Annotation
            value = annotation value1
            name = annotation name1
    Annotation名称:ysu.hxy.SomeAnnotation

    4. 限定Annotation使用对象@Target

        在定义Annotation类型时,使用java.lang.annotation.Target可以定义其适用的时机。在定义时要指定java.lang.annotation.ElementType的枚举值之一:

    Java代码 复制代码
    1. package ysu.hxy;   
    2.   
    3. public enum ElementType   
    4. {   
    5.     TYPE,  //适用class,interface,enum   
    6.     FIELD, //适用field   
    7.     METHOD,//适用method   
    8.     PARAMETER,  //适用method之上的parameter   
    9.     CONSTRUCTOR, //适用constructor   
    10.     LOCAL_VARIABLE, // 适用区域变量   
    11.    ANNOTATION_TYPE, //适用annotation类型   
    12.    PACKAGE  //适用package   
    13. }  

     举例说明,假设定义Annotation类型时,要限定它只能适用于构造函数与方法成员,则可以用以下代码来定义:

    Java代码 复制代码
    1. package ysu.hxy;   
    2.   
    3. import java.lang.annotation.Target;   
    4. import java.lang.annotation.ElementType;   
    5.   
    6. @Target({ElementType.CONSTRUCTOR,ElementType.METHOD})   
    7. public @interface MethodAnnotation{}  

     如果尝试将MethodAnnotation标示于类之上,例如:

    Java代码 复制代码
    1. @ysu.hxy.MethodAnnotation   
    2. public class SomeoneClass   
    3. {   
    4.     public void doSomething()   
    5.     {   
    6.         //....   
    7.     }   
    8. }  

     编译时会发生以下错误:

    D:\hxy>javac -d . SomeoneClass.java
    SomeoneClass.java:1: 注释类型不适用于该类型的声明
    @ysu.hxy.MethodAnnotation
    ^
    1 错误
    5. 要求为API文件的一部分@Documented

       在制作Java Doc文件时,并不会默认将Annotation的数据加入到文件中,例如设计了以下的OneAnnotaion类型:

    Java代码 复制代码
    1. package ysu.hxy;   
    2. public @interface OneAnnotation{}  

     并次之用在以下的程序中:

    Java代码 复制代码
    1. public class SomeoneClass   
    2. {   
    3.    @ysu.hxy.OneAnnotation   
    4.    public void doSomething()   
    5.    {   
    6.       //...   
    7.    }   
    8. }  
     

    试着使用javadoc程序来产生Java Doc文件,会以现文件中并不会有Annotation的相关信息。Annotation用于标示程序代码以便分析工具使用相关信息,有时Annotation包括了重要的信息,您也许会想要在使用者制作Java Doc文件的同时,也一并将Annotation的信息加入至API文件中,所以在定义Annotation类型时,可以使用java.lang.annotation.Documented。如下范例:

    Java代码 复制代码
    1. package ysu.hxy;   
    2.   
    3. import java.lang.annotation.Documented;   
    4. import java.lang.annotation.Retention;   
    5. import java.lang.annotation.RetentionPolicy;   
    6.   
    7. @Documented  
    8. @Retention(RetentionPolicy.RUNTIME)   
    9. public @interface TwoAnnotation{}  

      使用java.lang.annotation.Documented为定义的Annotation类型加上Annotation时,必须同时使用Retention来指定编译器将信息加入.class文件,并可以由VM读取,也就是要设定RententionPolicy为RUNTIME。接着可以使用这个Annotation,并产生Java Doc文件,这时可以看到文件中包括了@TwoAnnotation信息。

    6. 子类是否继承父类的annotation@Inherited

        在定义Annotation类型并使用于程序代码上后,默认父类中的Annotation并不会被继承至子类中。可以在定义Annotation类型时加上java.lang.Annotation.Inherited类型的Annotation,这让您定义的Annotation类型在被继承后仍可以保留在子类中。

    Java代码 复制代码
    1. package ysu.hxy;   
    2.   
    3. import java.lang.annotation.Retention;   
    4. import java.lang.annotation.RetentionPolicy;   
    5. import java.lang.annotaion.Inherited;   
    6.   
    7. @Retention(RetentionPolicy.RUNTIME}   
    8. @Inherited  
    9. public @interface ThreeAnnotation   
    10. {   
    11.    String value();   
    12.    String name();   
    13. }  

     可以在下面的程序中使用@ThreeAnnotaion:

    Java代码 复制代码
    1. public class SomeoneClass   
    2. {   
    3.     @ysu.hxy.ThreeAnnotation   
    4.     (   
    5.          value = "unit",   
    6.          name = "debug1"  
    7.     )   
    8.        
    9.     public void doSomething()   
    10.     {   
    11.         //....   
    12.     }   
    13. }  

     如果有一个类继承了SomeoneClass类,则理想上@ThreeAnnotation也会被继承下来。不过事实上@Inherited在Sun JDK 5.0里还没有作用。 

  • 相关阅读:
    easyUI 后台经典框架DEMO下载
    一个通过JSONP跨域调用WCF REST服务的例子(以jQuery为例)
    WCF的三个名称/命名空间,你是否傻傻分不清楚?
    未找到与约束ContractName Microsoft.VisualStudio.Text.ITextDocumentFactoryService... 匹配的导出 VS2012报错
    jquery easyui tabs单击刷新右键刷新
    在64位Windows7上安装64位Oracle11g
    Linux入门
    服务器硬件知识
    IP后面带/30 /29 /27等是什么意思?
    vitualbox安装centos7卡死
  • 原文地址:https://www.cnblogs.com/mabaishui/p/1777087.html
Copyright © 2011-2022 走看看