7.3 Java文档注释

Java 代码中的多数普通注释是用来说明代码实现细节的。不过,Java 语言规范还定义了一种特殊的注释,叫文档注释(doc comment),这种注释用于编写代码 API 的文档。

文档注释是普通的多行注释,以 /** 开头(不是通常使用的 /*),以 */ 结尾。文档注释放在类型或成员定义的前面,其中的内容是那个类型或成员的文档。文档中可以包含简单的 HTML 格式化标签,还可以包含其他特殊的关键字,提供额外的信息。编译器会忽略文档注释,但 javadoc 程序能把文档注释提取出来,自动转换成 HTML 格式的在线文档(javadoc 的更多信息参见第 13 章)。下面这个示例定义一个类,而且包含适当的文档注释:

  1. /**
  2. * 这个不可变的类表示<i>复数</i>
  3. *
  4. * @author David Flanagan
  5. * @version 1.0
  6. */
  7. public class Complex {
  8. /**
  9. * 保存复数的实部
  10. * @see #y
  11. */
  12. protected double x;
  13. /**
  14. * 保存复数的虚部
  15. * @see #x
  16. */
  17. protected double y;
  18. /**
  19. * 创建一个新Complex对象,表示复数x+yi
  20. * @param x 复数的实部
  21. * @param y 复数的虚部
  22. */
  23. public Complex(double x, double y) {
  24. this.x = x;
  25. this.y = y;
  26. }
  27. /**
  28. * 两个Complex对象相加,然后创建第三个对象,表示二者之和
  29. * @param c1 一个Complex对象
  30. * @param c2 另一个Complex对象
  31. * @return 一个新Complex对象,表示<code>c1</code>和<code>c2</code>之和
  32. * @exception java.lang.NullPointerException
  33. * 如果有一个参数是<code>null</code>
  34. */
  35. public static Complex add(Complex c1, Complex c2) {
  36. return new Complex(c1.x + c2.x, c1.y + c2.y);
  37. }
  38. }

7.3.1 文档注释的结构

文档注释主体的开头是一句话,概述类型或成员的作用。这句话可能会在文档的概述中显示,因此应该自成一体。第一句话后面可以跟着其他句子或段落,数量不限,这些内容用来详细说明类、接口、方法或字段。

在这些描述性段落之后,还可以有其他段落,数量也不限,而且每段都以一个特殊的文档注释标签开头,例如 @author@param@returns。这些包含标签的段落提供类、接口、方法或字段的特殊信息,javadoc 程序会以一种标准的方式显示这些信息。全部文档注释标签在下一节列出。

文档注释的描述性内容可以包含简单的 HTML 标记标签,例如: 用于强调, 用于显示类、方法和字段的名称,

  1.  
用于显示多行代码示例。除此之外,也可以包含

标签,把说明分成多个段落;还可以使用
  • 等相关标签,显示无序列表等结构。不过,要记住,你编写的内容会嵌入复杂的大型 HTML 文档,因此,文档注释不能包含 HTML 主结构标签,例如


    ,以防影响那个大型 HTML 文档的结构。

    在文档注释中,应该避免使用 标签加入超链接或交叉引用。如果有这方面的需求,应该使用特殊的文档注释标签 {@link}。这个标签和其他文档注释标签不同,可以在文档注释的任何位置使用。下一节会介绍,{@link} 标签的作用是插入超链接,指向其他类、接口、方法或字段,但无需知道 javadoc 程序使用的 HTML 结构约定和文件名。

    如果想在文档注释中插入图片,要把图片文件放在源码目录里的 doc-files 子目录中,而且要使用类名和一个整数后缀命名这个图片。例如,Circle 类文档注释中的第二张图片,可以使用下述 HTML 标签插入:

    1. <img src="doc-files/Circle-2.gif">

    文档注释中的各行都嵌在一个 Java 注释里,因此,处理之前,每一行注释前面的空格和星号都会删掉。所以,无需担心星号会出现在生成的文档中,也无需担心注释的缩进会影响

    1.  
    标签中代码示例的缩进。

    7.3.2 文档注释标签

    javadoc 程序能识别一些特殊的标签,每个标签都以 @ 字符开头。这些文档注释标签以一种标准的方式在注释中插入特殊的信息,javadoc 会根据所用的标签选择合适的格式输出信息。例如,@param 标签用于指定方法中一个参数的名称和意义。javadoc 会把这些信息提取出来,视情况而定,将其显示在 HTML 的

    列表或
    表格中。

    javadoc 能识别的文档注释标签如下所示,文档注释一般应该按照下述顺序使用这些标签。

    • @author name

    添加一个“Author:”条目,内容是指定的名字。每个类和接口定义都应该使用这个标签,但单个方法和字段一定不能使用。如果一个类有多位作者,在相邻的几行中使用多个 @author 标签。例如:

    1. @author Ben Evans
    2. @author David Flanagan

    多位作者按照时间顺序列出,先列出最初的作者。如果不知道作者是谁,可以使用“unascribed”1。如果不指定命令行参数 -authorjavadoc 不会输出作者信息。

    • @version text

    插入一个“Version:”条目,内容是指定的文本。例如:

    1. @version 1.32, 08/26/04

    每个类和接口的文档注释中都应该包含这个标签,但单个方法和字段不能使用。这个标签经常和支持自动排序版本号的版本控制系统一起使用,例如 git、Perforce 或 SVN。如果不指定命令行参数 -versionjavadoc 不会输出版本信息。

    • @param parameter-name description

    把指定的参数及其说明添加到当前方法的“Parameters:”区域。在方法和构造方法的文档注释中,每个参数都要使用一个 @param 标签列出,而且应该按照参数传入方法的顺序排列。这个标签只能出现在方法或构造方法的文档注释中。

    鼓励使用短语和句子片段,保持说明简洁。不过,如果需要详细说明参数,说明文字可以分成多行,需要多少字就写多少字。为了在源码中易于阅读,可以使用空格对齐所有说明。例如:

    1. @param o 要插入的对象
    2. @param index 插入对象的位置
    • @return description

    插入一个“Returns:”区域,内容是指定的说明。每个方法的文档注释中都应该使用这个标签,除非方法返回 void,或者是构造方法。说明需要多长就可以写多长,但为了保持简短,建议使用句子片段。例如:

    1. @return <code>true</code>:成功插入
    2. <code>false</code>:列表中已经包含要插入的对象
    • @exception full-classname description

    添加一个“Throws:”条目,内容是指定的异常名称和说明。方法和构造方法的文档注释应该为 throws 子句中的每个已检异常编写一个 @exception 标签。例如:

    1. @exception java.io.FileNotFoundException
    2. 如果找不到指定的文件

    如果方法的用户基于某种原因想捕获当前方法抛出的未检异常(即 RuntimeException 的子类),@exception 标签也可以为这些未检异常编写文档。如果方法能抛出多个异常,要在相邻的几行使用多个 @exception 标签,而且按照异常名称的字母表顺序排列。根据需要,说明可长可短,只要能说清异常的意思就行。这个标签只能出现在方法和构造方法的文档注释中。@throws 标签是 @exception 标签的别名。

    • @throws full-classname description

    这个标签是 @exception 标签的别名。

    • @see reference

    添加一个“See Also:”条目,内容是指定的引用。这个标签可以出现在任何文档注释中。引用的句法在 7.3.4 节说明。

    • @deprecated explanation

    这个标签指明随后的类型或成员弃用了,应该避免使用。javadoc 会在文档中添加一个明显的“Deprecated”条目,内容为指定的 explanation 文本。这个文本应该说明这个类或成员从何时开始弃用,如果可能的话,还要推荐替代的类或成员,并且添加指向替代的类或成员的链接。例如:

     @deprecated3.0版开始,这个方法被{@link #setColor}取代了。

    一般情况下,javac 会忽略所有注释,但 @deprecated 标签是个例外。如果文档注释中有这个标签,编译器会在生成的类文件中注明弃用信息,提醒其他类,这个功能已经弃用。

    • @since version

    指明类型或成员何时添加到 API 中。这个标签后面应该跟着版本号或其他形式的版本信息。例如:

    1. @since JNUT 3.0

    每个类型的文档注释都应该包含一个 @since 标签;类型初始版本之后添加的任何成员,都要在其文档注释中加上 @since 标签。

    • @serial description

    严格来说,类序列化的方式是公开 API 的一部分。如果你编写的类可以序列化,就应该在文档注释中使用 @serial 标签和下面列出的相关标签说明序列化的格式。在实现 Serializable 接口的类中,组成序列化状态的每个字段,都应该在其文档注释中使用 @serial 标签。

    对于使用默认序列化机制的类来说,除了声明为 transient 的字段,其他所有字段,包括声明为 private 的字段,都要在文档注释中使用 @serial 标签。description 应该简要说明字段及其在序列化对象中的作用。

    在类和包的文档注释中也可以使用 @serial 标签,指明是否为当前类或包生成“Serialized Form”页面。句法如下:

    1. @serial include
    2. @serial exclude
    • @serialField name type description

    实现 Serializable 接口的类可以声明一个名为 serialPersistentFields 的字段,定义序列化格式。serialPersistentFields 字段的值是一个数组,由 ObjectStreamField 对象组成。对这样的类来说,在 serialPersistentFields 字段的文档注释里,数组中的每个元素都要使用一个 @serialField 标签列出,每个标签都要指明元素在类序列化状态中的名称、类型和作用。

    • @serialData description

    实现 Serializable 接口的类可以定义一个 writeObject() 方法,用于写入数据,代替默认序列化机制提供的写入方式。实现 Externalizable 接口的类可以定义一个 writeExternal() 方法,把对象的完整状态写入序列化流。writeObject()writeExternal() 方法的文档注释中应该使用 @serialData 标签,description 应该说明这个方法使用的序列化格式。

    1这个单词可以理解为中文里的“佚名”。——译者注

    7.3.3 行内文档注释标签

    除了上述标签外,javadoc 还支持几个行内标签。在文档注释中,只要能使用 HTML 文本的地方都可以使用行内标签。因为这些标签直接出现在 HTML 文本流中,所以要使用花括号把标签中的内容和周围的 HTML 文本隔开。javadoc 支持的行内标签包括如下几个。

    • {@link reference }

    {@link} 标签和 @see 标签的作用类似,但 @see 标签是在专门的“See Also:”区域放一个指向引用的链接,而 {@link} 标签在行内插入链接。在文档注释中,只要能使用 HTML 文本的地方都可以使用 {@link} 标签。因此,{@link} 标签可以出现在类、接口、方法或字段的第一句话中,也能出现在 @param@returns@exception@deprecated 标签的说明中。{@link} 标签中的 reference 使用专门的句法,7.3.4 节会介绍。例如:

    @param regexp 搜索时使用的正则表达式。这个字符串参数使用的句法必须符合{@link java.util.regex.Pattern}制定的规则。

    • {@linkplain reference }

    {@linkplain} 标签和 {@link} 标签的作用类似,不过,在 {@linkplain} 标签生成的链接中,链接文字使用普通的字体,而 {@link} 标签使用代码字体。如果 reference 包含要链接的 feature 和指明链接替代文本的 label,就要使用 {@linkplain} 标签。7.3.4 节会讨论 reference 参数中的 featurelabel 两部分。

    • {@inheritDoc}

    如果一个方法覆盖了超类的方法,或者实现了接口中的方法,那么这个方法的文档注释可以省略一些内容,让 javadoc 自动从被覆盖或被实现的方法中继承。{@inheritDoc} 标签可以继承单个标签的文本,还能在继承的基础上再添加一些说明。继承单个标签的方式如下:

    1. @param index @{inheritDoc}
    2. @return @{inheritDoc}
    • {@docRoot}

    这个行内标签没有参数,javadoc 生成文档时会把它替换成文档的根目录。这个标签在引用外部文件的超链接中很有用,例如引用一张图片或者一份版权声明:

     7.3 Java文档注释 - 图1这份资料受版权保护

    • {@literal text }

    这个行内标签按照字面形式显示 texttext 中的所有 HTML 都会转义,而且所有 javadoc 标签都会被忽略。虽然不保留空白格式,但仍适合在

    1.  
    标签中使用。

    • {@code text }

    这个标签和 {@literal} 标签的作用类似,但会使用代码字体显示 text 的字面量。等价于:

    1. &lt;code&gt;{@literal <replaceable>text</replaceable>}&lt;/code&gt;
    • {@value}

    没有参数的 {@value} 标签在 static final 字段的文档注释中使用,会被替换成当前字段的常量值。

    • {@value reference }

    这种 {@value} 标签的变体有一个 reference 参数,指向一个 static final 字段,会被替换成指定字段的常量值。

    7.3.4 文档注释中的交叉引用

    @see 标签以及行内标签 {@link}{@linkplain}{@value} 都可以创建指向文档中其他内容的交叉引用,而且往往指向其他类型或成员的文档注释。

    reference 参数有三种不同的格式。如果 reference 以引号开头,表示书名或其他出版物的名称,参数的值是什么就显示什么。如果 reference< 符号开头,表示使用 标签标记的任意 HTML 超链接,这个超链接会原封不动地插入生成的文档。@see 标签使用这种形式插入指向其他在线文档的链接,例如程序员指南或用户手册。

    如果 reference 既不是放在引号中的字符串,也不是超链接,那么应该具有下述格式:

    1. feature [label]

    此时,javadoc 会把 label 当成超链接的文本,指向 feature 指定的内容。如果没指定 label(一般都不指定),javadoc 会使用 feature 作为超链接的文本。

    feature 可以指向包、类型或类型的成员,使用下述格式中的一种。

    • pkgname

    指向指定的包。例如:

    1. @see java.lang.reflect
    • pkgname.typename

    指定完整的包名,指向对应的类、接口、枚举类型或注解类型。例如:

    1. @see java.util.List
    • typename

    不指定包名,指向对应的类型。例如:

    1. @see List

    javadoc 会搜索当前包和 typename 类导入的所有类,解析这个引用。

    • typename#methodname

    指向指定类型中指定名称对应的方法或构造方法。例如:

    1. @see java.io.InputStream#reset
    2. @see InputStream#close

    如果类型不包含包名,会按照 typename 使用的方式解析。如果方法重载了,或类中定义有同名字段,这种句法会引起歧义。

    • typename#methodname(paramtypes)

    指向某个方法或构造方法,而且明确指定参数的类型。交叉引用重载的方法时可以使用这种格式。例如:

    1. @see InputStream#read(byte[], int, int)
    • #methodname

    指向一个没有重载的方法或构造方法,这个方法在当前类或接口中,或者在当前类或接口的某个外层类、超类或超接口中。这种简短格式用于指向同一个类中的其他方法。例如:

    1. @see #setBackgroundColor
    • #methodname(paramtypes)

    指向当前类、接口或者某个超类、外层类中的方法或构造方法。这种格式可以指向重载的方法,因为它明确列出了方法参数的类型。例如:

    1. @see #setPosition(int, int)
    • typename#fieldname

    指向指定类中的指定字段。例如:

    1. @see java.io.BufferedInputStream#buf

    如果类型不包含包名,会按照 typename 使用的方式解析。

    • #fieldname

    指向一个字段,这个字段在当前类型中,或者在当前类型的某个外层类、超类或超接口中。例如:

    1. @see #x

    7.3.5 包的文档注释

    类、接口、方法、构造方法和字段的文档注释放在这些结构的定义体之前。javadoc 也能读取并显示包的概述文档。包在一个目录中定义,而不是在单个源码文件中定义,因此,javadoc 会在包所在的目录(存放包中各个类的源码)中需找一个名为 package.html 的文件,这个文件中的内容就是包的文档。

    package.html 文件可以包含简单的HTML格式文档,也可以使用 @see@link@deprecated@since 标签。因为 package.html 不是 Java 源码文件,所以其中的文档应该是 HTML,而不能是 Java 注释(即不能包含在 /***/ 之间)。最后,在 package.html 文件中,所有 @see@link 标签都必须使用完全限定的类名。

    除了可以为每个包定义 package.html 文件之外,还可以为一组包提供概括性文档,方法是在这组包所在的源码树中创建一个 overview.html 文件。javadoc 解析这个源码树时,会提取 overview.html 文件中的内容,作为最高层概览显示出来。