注释是一种形式的元数据,提供了非程序自身的数据,注释对于被注释的代码没有直接的影响。
本文主要概括注释的使用,java平台(SE)预定义的注释,类型注释是如跟可插入类型系统连用达到更强的类型检查的,以及如何实现重复注释。
注释有许多用途,包括:
- 为编译器提供信息--编译器可以利用注释检查错误或者抑制警告信息
- 编译时或者部署时处理--软件工具可以处理注释并生成代码,XML文件等等
- 运行时处理--有些注释在运行时可以被检测到
注释格式
注释最简单的形式如下:
@Entity
@符号提示编译器接下来的词是一个注释,示例中注释为Entity,注释中可以包含元素,元素可以是命名的也可以是未命名的,如果注释中仅有一个元素,则元素名称可以省略,如果注释中不含元素,则圆括号可以省略,可以在一个声明中使用多个注释,java8中可以允许使用多个相同名称的注释,又叫重复注释:
//注释中包含元素 @Author( name = "Benjamin Franklin", date = "3/27/2003" ) class MyClass() { //注释中只有一个元素,则名称可省略 @SuppressWarnings("unchecked") void myMethod() { ... } //... }
注释使用的位置
注释可以应用于声明中,包括类,字段,方法和其他变成元素的声明。一般情况下,每个注释占用一行。
java8 以后,注释也可以在类型使用的使用的时候应用,如下所示:
//类实例床架表达式 new @Interned MyObject(); //类型转化 myString = (@NonNull String) str; //实现短语 class UnmodifiableList<T> implements @Readonly List<@Readonly T> { ... } //抛出异常声明 void monitorTemperature() throws @Critical TemperatureException { ... }
所有注释的形式叫做类型注释。
声明注释
注释的声明示例:
@interface ClassPreamble { String author(); String date(); int currentRevision() default 1;}
注释的定义类似于接口,只不过interface关键词前有@符号,实际上注释类型是一种形式接口,注释的主体定义包含了注释的元素声明,元素可以有默认值,添加默认值的方法就是在元素声明后跟上default关键词以及默认值,如上例子所示。
预定义注释类型
java se API中预定义了多个注释类型,其中有一些是被java编译器用的,有一些是应用与其他注释的。
java语言使用的注释
在java.lang包中预定义的注释类型有@Deprecated,@Override和SupressWarning。
@Deprecated提示所注释的元素已经弃用,不应该再使用。当一个被@Deprecated注释所注释的方法,类或者字段被使用时,编译器将产生警告信息。当决定要弃用一个元素时,也应该在javadoc中体现,利用javadoc的@deprecated标签,如下例所示,javadoc标签以小写字母开头:
// Javadoc此处写javadoc注释 /** * @deprecated * explanation of why it was deprecated */ @Deprecated static void deprecatedMethod() { } }
@Override注释用于通知编译器该注释所注释的方法将覆写父类中的方法,当然,覆写方法不需要用@Override注释,@Override注释的使用能减少错误,如方法名称拼写错误,如果没有成功覆写方法,则编译器将产生错误。
@SuppressWarnings注释通知编译器抑制指定的错误信息的产生,每条错误信息都属于一个类型,java语言说明书中列出了两种错误信息:deprecation和unchecked。
@SafeVarargs(java7及以后)注释应用于方法或者构造器上,使用注释时,含有可变变量的方法或者构造器将不会因为对可变变量的可能不安全的操作产生unchecked警告信息。
@FunctionalInterface注释在java8中引入,使用该注释表明被注释的接口为功能接口。
其他注释使用的注释
被用于其他注释的注释叫做元注释(meta-annotations),java.lang.annotation中有多个元注释。
@Retention注释指定如何存储标记的注释:
RetentionPolicy.SOURCE
– 标记的注释仅仅保留在源代码层,被编译器忽略RetentionPolicy.CLASS
– 标记的注释在编译时被保留,但是会被java虚拟机忽略RetentionPolicy.RUNTIME
– 标记的注释在java虚拟机中保留,但是在运行时被忽略
@Documented注释提示指定的注释在使用时也应该使用javadoc工具撰写文档。
@Target注释用来限制标记的注释所使用的对象,该注释指定以下元素类型中的一个作为其值:
ElementType.ANNOTATION_TYPE
能应用于一个注释ElementType.CONSTRUCTOR
能应用于一个构造器ElementType.FIELD
能应用与一个注释或者属性ElementType.LOCAL_VARIABLE
能应用于一个局部变量ElementType.METHOD
能应用于方法层的注释ElementType.PACKAGE
能应用于包声明ElementType.PARAMETER
能应用于一个方法的参数ElementType.TYPE
能应用于一个类
@Inherited注释提示标记的注释类型可以从超类继承(默认不能继承),当用户未检索到该类型的注释时,将在其父类中检索该注释,该注释仅能在类的声明中使用。
@Repeatable注释是从java8开始引入的,提示标记的类型可以对同一个元素使用多次。
类型注释和可插入类型系统
java8以前,注释只能用在声明当中,java8以后,注释可以应用于任何类使用的地方,比如类实例的创建表达式(new),转化(cast),实现子句以及抛出子句(以上注释的使用位置已举例)。
类型注释的常见可用于支持改进的类型检查的java编程方式的分析。java8 SE自身并没有提供类型检查的框架,但你可以编写或者是下载一个由一个或多个用于结合java编译器的模块而实现的类型检查框架,如华盛顿大学编写的检查框架Checker Framework。
检索注释
Reflection API中由多个方法可以用来检索注释,返回单个注释的方法,如AnnotatedElement.getAnnotationByType(Class<T>),其行为没有发生改变,java8以后,由于可以重复使用一个类型的注释,由于兼容的原因,重复的注释是存储在一个注释容器内的,由java编译器自动生成,因此当有重复注释时,可先获得多个注释的注释容器,这样传统返回单个注释的方法照样可以使用。java8也引入了一个可以一次返回多个注释的方法,如AnnotatedElement.getAnnotations(Class<T>)。