JAVA Annotation

注释(一种元数据形式)提供有关不属于程序本身的程序的数据。注释对它们注释的代码的操作没有直接影响。

注释有许多用途,其中包括:

  • 编译器的信息 - 编译器可以使用注释来检测错误或抑制警告。
  • 编译时和部署时处理 - 软件工具可以处理注释信息以生成代码,XML文件等。
  • 运行时处理 - 可以在运行时检查某些注释。

    注释基础知识

    注释的格式

    在最简单的形式中,注释如下所示:

    @实体
    

    at符号(@)向编译器指示后面的内容是注释。在以下示例中,注释的名称为Override

    @覆盖
    void mySuperMethod(){...}
    

    注释可以包含可以命名或未命名的元素,并且这些元素有值:

    @作者(
       name =“本杰明富兰克林”,
       date =“3/27/2003”
    class MyClass(){...}
    

    要么

    @SuppressWarnings(value =“unchecked”)
    void myMethod(){...}
    

    如果只有一个名为的元素value,那么名称可以省略,如:

    @SuppressWarnings( “未登记”)
    void myMethod(){...}
    

    如果注释没有元素,则可以省略括号,如上例所示@Override

    也可以在同一声明中使用多个注释:

    @Author(name =“Jane Doe”)
    @EBook
    class MyClass {...}
    

    如果注释具有相同的类型,则称为重复注释:

    @Author(name =“Jane Doe”)
    @Author(姓名=“约翰史密斯”)
    class MyClass {...}
    

    从Java SE 8发行版开始,支持重复注释。

    注释类型可以是Java SE API java.langjava.lang.annotation中定义的类型之一在前面的例子,Override并且SuppressWarnings是 预定义的Java注解也可以定义自己的注释类型。AuthorEbook前面例子中的注释是自定义的注释类型。

    可以使用注释的位置

    注释可以应用于声明:类,字段,方法和其他程序元素的声明。当在声明中使用时,每个注释通常按照惯例出现在它自己的行上。

    从Java SE 8发行版开始,注释也可以应用于类型使用这里有些例子:

    • 类实例创建表达式:
          new @Interned MyObject();
      
    • 输入:
          myString =(@ NonNull String)str;
      
    • implements 条款:
          class UnmodifiableList <T>实现
              @Readonly List <@Readonly T> {...}
      
    • 抛出的异常声明:
          void monitorTemperature()抛出
              @Critical TemperatureException {...}

      声明注释类型

      许多注释会替换代码中的注释。

      假设一个软件组传统上启动每个类的主体,并提供重要信息的注释:

      public class Generation3List扩展Generation2List {
      
         //作者:John Doe
         //日期:3/17/2002
         //当前版本:6
         //最后修改时间:4/12/2004
         //作者:Jane Doe
         //评论者:Alice,Bill,Cindy
      
         //类代码到这里
      
      }
      

      要使用注释添加此相同元数据,必须先定义注释类型这样做的语法是:

      @interface ClassPreamble {
         String author();
         字符串日期();
         int currentRevision()默认1;
         String lastModified()默认为“N / A”;
         String lastModifiedBy()默认为“N / A”;
         //注意使用数组
         String [] reviewers();
      }
      

      注释类型定义类似于接口定义,其中关键字interface前面是at符号(@)(@ = AT,与注释类型一样)。注释类型是一种界面形式,将在后面的课程中介绍。目前,您不需要了解接口。

      前一个注释定义的主体包含注释类型元素声明,它看起来很像方法。请注意,他们可以定义可选的默认值。

      定义注释类型后,您可以使用该类型的注释,并填入值,如下所示:

      @ClassPreamble(
         author =“John Doe”,
         date =“3/17/2002”,
         currentRevision = 6,
         lastModified =“4/12/2004”,
         lastModifiedBy =“Jane Doe”,
         //注意数组表示法
         评论者= {“爱丽丝”,“鲍勃”,“辛迪”}
      public class Generation3List扩展Generation2List {
      
      //类代码到这里
      
      }
      

      注意:  要使信息@ClassPreamble显示在Javadoc生成的文档中,您必须使用注释注释@ClassPreamble定义@Documented
      //导入它以使用 @Documented
      import java.lang.annotation。*;
      
      @Documented
      @interface ClassPreamble {
      
         //注释元素定义
         
      }

      预定义的注释类型

      Java SE API中预定义了一组注释类型。Java编译器使用某些注释类型,有些注释类型适用于其他注释。

      Java语言使用的注释类型

      中定义的预定义的注释类型java.lang@Deprecated@Override,和@SuppressWarnings

      @Deprecated @Deprecated注释表示已弃用标记的元素,不应再使用。只要程序将方法,类或字段与@Deprecated注释一起使用,编译器就会生成警告不推荐使用元素时,也应使用Javadoc @deprecated标记对其进行记录,如以下示例所示。@在Javadoc注释和注释中使用at符号()并非巧合:它们在概念上是相关的。另请注意,Javadoc标记以小写d开头,注释以大写D开头

         // Javadoc评论如下
          / **
           * @deprecated 
           * 解释为何弃用它
           * /
          @Deprecated
          static void deprecatedMethod(){}
      }
      

      @Override @Override注释通知编译器该元素旨在覆盖超类中声明的元素。将在接口和继承中讨论重写方法 。

         // 将方法标记为超类方法 
         // 已被覆盖
         @Override 
         int overriddenMethod(){}
      

      虽然在重写方法时不需要使用此批注,但它有助于防止出错。如果标记的方法@Override无法正确覆盖其某个超类中的方法,则编译器会生成错误。

      @SuppressWarnings @SuppressWarnings释告诉编译器抑制它否则会生成的特定警告。在以下示例中,使用了不推荐使用的方法,编译器通常会生成警告。但是,在这种情况下,注释会导致警告被抑制。

         // 使用弃用的方法告诉  
         // 编译器不要生成警告
         @SuppressWarnings(“deprecation”)
          void useDeprecatedMethod(){
              //弃用警告
              //  - 被压制
              objectOne.deprecatedMethod();
          }
      

      每个编译器警告都属于一个类别。Java语言规范列出了两个类别:deprecationunchecked。在unchecked与来临之前,旧代码交互时,会发生警告 仿制药。要禁止多种类别的警告,请使用以下语法:

      @SuppressWarnings({“unchecked”,“deprecation”})
      

      @SafeVarargs @SafeVarargs注释在应用于方法或构造函数时,断言代码不对其varargs参数执行可能不安全的操作。使用此注释类型时,varargs将禁止与使用相关的未经检查的警告。

      @FunctionalInterfaceJava SE 8中引入的@FunctionalInterface注释表明类型声明旨在成为Java语言规范定义的功能接口。

      适用于其他注释的注释

      适用于其他注释的注释称为元注释。在中定义了几种元注释类型java.lang.annotation

      @Retention @Retention annotation指定标记注释的存储方式:

      • RetentionPolicy.SOURCE - 标记的注释仅保留在源级别中,并由编译器忽略。
      • RetentionPolicy.CLASS - 标记的注释在编译时由编译器保留,但Java虚拟机(JVM)会忽略。
      • RetentionPolicy.RUNTIME - 标记的注释由JVM保留,因此运行时环境可以使用它。

      @Documented @Documented注释表明,无论何时使用指定的注释,都应使用Javadoc工具记录这些元素。(默认情况下,注释不包含在Javadoc中。)

      @Target @Target注释标记另一个注释,以限制可以应用注释的Java元素类型。目标注释指定以下元素类型之一作为其值:

      • ElementType.ANNOTATION_TYPE 可以应用于注释类型。
      • ElementType.CONSTRUCTOR 可以应用于构造函数。
      • ElementType.FIELD 可以应用于字段或属性。
      • ElementType.LOCAL_VARIABLE 可以应用于局部变量。
      • ElementType.METHOD 可以应用于方法级注释。
      • ElementType.PACKAGE 可以应用于包声明。
      • ElementType.PARAMETER 可以应用于方法的参数。
      • ElementType.TYPE 可以应用于类的任何元素。

      @Inherited @Inherited注释表明注释类型可以从超类继承。(默认情况下不是这样。)当用户查询注释类型并且该类没有此类型的注释时,将查询类的超类以获取注释类型。此注释仅适用于类声明。

      @RepeatableJava SE 8中引入的@Repeatable注释表明标记的注释可以多次应用于相同的声明或类型使用。

      类型注释和可插入类型系统

      在Java SE 8发行版之前,注释只能应用于声明。从Java SE 8发行版开始,注释也可以应用于任何类型的使用这意味着可以在使用类型的任何位置使用注释。使用where类型的一些示例是类实例创建表达式(new),强制转换,implements子句和throws子句。这种注释形式称为类型注释注释基础知识中提供了几个示例 。

      创建类型注释是为了支持改进的Java程序分析,以确保更强的类型检查。Java SE 8版本不提供类型检查框架,但它允许您编写(或下载)类型检查框架,该框架实现为与Java编译器结合使用的一个或多个可插入模块。

      例如,您希望确保程序中的特定变量永远不会分配给null; 你想避免触发a NullPointerException您可以编写自定义插件来检查此问题。然后,您将修改代码以注释该特定变量,表明它永远不会分配给null。变量声明可能如下所示:

      @NonNull String str;
      

      当您编译代码(包括NonNull命令行中模块)时,编译器会在检测到潜在问题时输出警告,允许您修改代码以避免错误。在更正代码以删除所有警告后,程序运行时不会发生此特定错误。

      您可以使用多个类型检查模块,其中每个模块检查不同类型的错误。通过这种方式,您可以构建在Java类型系统之上,在您希望的时间和地点添加特定的检查。

      通过明智地使用类型注释和可插入类型检查器的存在,您可以编写更强大且更不容易出错的代码。

      在许多情况下,您不必编写自己的类型检查模块。有第三方为您完成了这项工作。例如,您可能希望利用华盛顿大学创建的Checker Framework。该框架包括一个NonNull模块,一个正则表达式模块和一个互斥锁模块。

      重复注释

      在某些情况下,您希望将相同的注释应用于声明或类型用途。从Java SE 8发行版开始,重复注释使您可以执行此操作。

      例如,您正在编写代码以使用计时器服务,该服务使您能够在给定时间或某个计划上运行方法,类似于UNIX cron服务。现在,您要设置一个计时器以在该月的最后一天和每个星期五晚上11:00 运行方法doPeriodicCleanup。要设置要运行的计时器,请创建一个@Schedule注释并将其应用于doPeriodicCleanup方法两次第一次使用指定月份的最后一天,第二次使用指定星期五晚上11点,如下面的代码示例所示:

      @Schedule(请将dayOfMonth = “最后”)
      @Schedule(dayOfWeek =“Fri”,小时=“23”)
      public void doPeriodicCleanup(){...}
      

      前面的示例将注释应用于方法。您可以在使用标准注释的任何位置重复注释。例如,您有一个用于处理未授权访问异常的类。@Alert为管理员注释了一个注释,为管理员注释了另一个注释:

      @Alert(角色= “经理人”)
      @Alert(角色= “管理员”)
      public class UnauthorizedAccessException扩展SecurityException {...}
      

      出于兼容性原因,重复注释存储在由Java编译器自动生成容器注释中。为了使编译器执行此操作,代码中需要两个声明。

      第1步:声明可重复的注释类型

      注释类型必须使用@Repeatable元注释标记以下示例定义了自定义@Schedule可重复注释类型:

      import java.lang.annotation.Repeatable;
      
      @Repeatable(Schedules.class)
      public @interface Schedule {
        String dayOfMonth()默认为“first”;
        String dayOfWeek()默认为“Mon”;
        int hour()默认为12;
      }
      

      @Repeatable括号 中的元注释的值是Java编译器为存储重复注释而生成的容器注释的类型。在此示例中,包含注释类型是Schedules,因此重复@Schedule注释存储在@Schedules注释中。

      将相同的注释应用于声明而不首先声明它是可重复的,这会导致编译时错误。

      第2步:声明包含注释类型

      包含注释类型必须具有value数组类型元素。数组类型的组件类型必须是可重复的注释类型。Schedules包含注释类型的声明如下:

      public @interface Scheduleles {
          Schedule [] value();
      }
      

      检索注释

      Reflection API中有几种可用于检索注释的方法。返回单个注释的方法例如 AnnotatedElement.getAnnotation(Class <T>))的行为未更改,因为如果存在所请求类型的一个注释,它们仅返回单个注释。如果存在多个所请求类型的注释,则可以通过首先获取其容器注释来获取它们。通过这种方式,遗留代码继续工作。Java SE 8中引入了其他方法,它们扫描容器注释以一次返回多个注释,例如 AnnotatedElement.getAnnotationsByType(Class <T>)。请参阅 AnnotatedElement 有关所有可用方法的信息的类规范。

      设计注意事项

      设计注释类型时,必须考虑该类型注释基数现在可以使用注释零次,一次,或者,如果注释的类型被标记为@Repeatable多次,则不止一次。还可以通过使用@Target元注释来限制可以使用注释类型的位置例如,您可以创建只能在方法和字段上使用的可重复注释类型。仔细设计注释类型非常重要,以确保使用注释的程序员发现它尽可能灵活和强大。

posted @ 2019-03-13 17:58  秋宝。  阅读(74)  评论(0编辑  收藏  举报