zoukankan      html  css  js  c++  java
  • Annotation

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

    Annotation工作方式
    从Java5.0版发布以来,5.0平台提供了一个正式的annotation功能:
    允许开发者定义、使用自己的annotation类型。
    此功能由一个定义annotation类型的语法和一个描述annotation声明的语法,读取annotation的API,一个使用annotation修饰的class文件,一个annotation处理工具(apt)组成。
    annotation并不直接影响代码语义,但是它能够工作的方式被看作类似程序的工具或者类库,它会反过来对正在运行的程序语义有所影响。
    annotation可以从源文件、class文件或者以在运行时反射的多种方式被读取。
    当然annotation在某种程度上使javadoc tag更加完整。
    一般情况下,如果这个标记对java文档产生影响或者用于生成java文档的话,它应该作为一个javadoc tag;否则将作为一个annotation。
     

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

      

    定义Marker Annotation,也就是Annotation名称本身即提供信息
    对于程序分析工具来说,主要是检查是否有MarkerAnnotation的出现,并作出对应的动作  
     
    value成员设定默认值,用"default"关键词
    数组方式的使用
    枚举在Annotation中的应用
     //用@interface定义一个Annotation
    public @interface AnnotationTest {
     // String value() default "langsin";
     //定义一个名为value的变量,这是Annotation变量的定义方式,缺省值为"langsin"
     enumTest value1() default enumTest.Hello;
    // 定义类型为8种原生类型,字符串类型,枚举类型,一维数组类型,Class类类型,Annotation类型。
    }

    enum enumTest {
     Hello, World, Welcome
    };

     
    使用@interface自行定义Annotation型态时,实际上是自动继承了java.lang.annotation.Annotation接口
    由编译程序自动为您完成其它产生的细节
    在定义Annotation型态时,不能继承其它的Annotation型态或是接口
     
    定义Annotation型态时也可以使用包来管理类别
    方式类同于类的导入功能

    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信息

    参见程序
     @Retention(RetentionPolicy.RUNTIME)//只有RUNTIME才能被VM读取,才能进行反射
    public @interface MyAnnotation {
     String hello() default "langsin";
     String world();
    }
     
    使用java.lang.annotation.Target可以定义其使用之时机
    在定义时要指定java.lang.annotation.ElementType的枚举值之一
     
    public enum ElementType
    {
         TYPE, //适用class, interface, enum
         FIELD, //适用field
         METHOD, //适用method
         PARAMETER, //适用method上之parameter
         CONSTRUCTOR, //适用constructor
         LOCAL_VARIABLE, //适用局部变量
         ANNOTATION_TYPE, //适用annotation型态
         PACKAGE //适用package
    }
    参见范例
     public class MyTargetTest {
     @MyTarget(value = "xyz")
     public void doSomething(){
      System.out.println("hello world");
     }
    }
     
    想要在使用者制作JavaDoc文件的同时,也一并将Annotation的讯息加入至API文件中
    使用java.lang.annotation.Documented
     Project-->Generate JavaDoc-->指定要生成JavaDoc的类及生成的存放路径。
    @Documented
    public @interface DocumentedAnnotation {
     String hello();
    }
    public class DocumentedTest {
     /**
      * This is the comments that I have added
      */
     @DocumentedAnnotation(hello = "welcome")
     public void method(){
      System.out.println("hello world");
     }
    }
     
    预设上父类别中的Annotation并不会被继承至子类别中
    可以在定义Annotation型态时加上java.lang.annotation.Inherited型态的Annotation
     @Inherited
    @Retention(RetentionPolicy.RUNTIME)
    public @interface InheritedTest {
     String value();
    }
     
    @InheritedTest(value = "langsin")
    public class Parent {
     public void doSomething(){
      System.out.println("hello");
     }
    }
     
    public class Child extends Parent {
     public void doSomething(){
      
     }
    }
     
    public class Test {
     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);
      }
     }
    }
  • 相关阅读:
    mysql 表的类型
    【Mysql优化】key和index区别
    [置顶] 步步辨析JS中的对象成员
    [置顶] C语言单元测试框架
    代码规范总结
    AFNetworking、MKNetworkKit和ASIHTTPRequest对比
    在SQL中使用PL/SQL函数存在的问题
    C++中一个函数隐藏的有趣例子
    深入浅出Mybatis-分页
    SRM 207 Div II Level Two: RegularSeason,字符串操作(sstream),多关键字排序(操作符重载)
  • 原文地址:https://www.cnblogs.com/mingforyou/p/2285312.html
Copyright © 2011-2022 走看看