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.lang
或java.lang.annotation
包中定义的类型之一。在前面的例子,Override
并且SuppressWarnings
是 预定义的Java注解。也可以定义自己的注释类型。在Author
与Ebook
前面例子中的注释是自定义的注释类型。可以使用注释的位置
注释可以应用于声明:类,字段,方法和其他程序元素的声明。当在声明中使用时,每个注释通常按照惯例出现在它自己的行上。
从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语言规范列出了两个类别:
deprecation
和unchecked
。在unchecked
与来临之前,旧代码交互时,会发生警告 仿制药。要禁止多种类别的警告,请使用以下语法:@SuppressWarnings({“unchecked”,“deprecation”})
@SafeVarargs
@SafeVarargs
注释在应用于方法或构造函数时,断言代码不对其varargs
参数执行可能不安全的操作。使用此注释类型时,varargs
将禁止与使用相关的未经检查的警告。@FunctionalInterface
Java 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
注释表明注释类型可以从超类继承。(默认情况下不是这样。)当用户查询注释类型并且该类没有此类型的注释时,将查询类的超类以获取注释类型。此注释仅适用于类声明。@Repeatable
Java 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
元注释来限制可以使用注释类型的位置。例如,您可以创建只能在方法和字段上使用的可重复注释类型。仔细设计注释类型非常重要,以确保使用注释的程序员发现它尽可能灵活和强大。
- 类实例创建表达式: