目錄
前言
一. Java 文檔和 javadoc
二. 文檔注釋的格式
1. 文檔注釋的格式化
2. 文檔注釋的三部分
三. 使用 javadoc 標記
1. @see 的使用
2. 使用 @author、@version 說(shuō)明類(lèi)
3. 使用 @param、@return 和 @exception 說(shuō)明方法
四. javadoc 命令
Java 的語(yǔ)法與 C++ 及為相似,那么,你知道 Java 的注釋有幾種嗎?是兩種?
// 注釋一行
/* ...... */ 注釋若干行
不完全對,除了以上兩種之外,還有第三種,文檔注釋?zhuān)?/p>
/** ...... */ 注釋若干行,并寫(xiě)入 javadoc 文檔
通常這種注釋的多行寫(xiě)法如下:
/**
* .........
* .........
*/
暫停,暫停!這第三種注釋有什么用?javadoc 又是什么東西?
好,那就讓我告訴你——
Java 程序員都應該知道使用 JDK 開(kāi)發(fā),最好的幫助信息就來(lái)自 SUN 發(fā)布的 Java 文檔。它分包、分類(lèi)詳細的提供了各方法、屬性的幫助信息,具有詳細的類(lèi)樹(shù)信息、索引信息等,并提供了許多相關(guān)類(lèi)之間的關(guān)系,如繼承、實(shí)現接口、引用等。
Java 文檔全是由一些 html 文件組織起來(lái)的,在 SUM 的站點(diǎn)上可以下載它們的壓縮包。但是你肯定想不到,這些文檔我們可以自己生成?!痛舜蜃?,再吊一次胃口。
安裝了 JDK 之后,安裝目錄下有一個(gè) src.jar 文件或者 src.zip 文件,它們都是以 ZIP 格式壓縮的,可以使用 WinZip 解壓。解壓之后,我們就可以看到分目錄放的全是 .java 文件。是了,這些就是 Java 運行類(lèi)的源碼了,非常完整,連注釋都寫(xiě)得一清二楚……不過(guò),怎么看這些注釋都有點(diǎn)似曾相識的感覺(jué)?
這就不奇怪了,我們的迷底也快要揭開(kāi)了。如果你仔細對比一下 .java 源文件中的文檔注釋 (/** ... */) 和 Java 文檔的內容,你會(huì )發(fā)現它們就是一樣的。Java 文檔只是還在格式和排版上下了些功夫。再仔細一點(diǎn),你會(huì )發(fā)現 .java 源文件中的注釋還帶有 HTML 標識,如 <B>、<BR>、<Code> 等,在 Java 文檔中,該出現這些標識的地方,已經(jīng)按標識的的定義進(jìn)行了排版。
終于真像大白了,原來(lái) Java 文檔是來(lái)自這些注釋。難怪這些注釋叫做文檔注釋呢!不過(guò),是什么工具把這些注釋變成文檔的呢?
是該請出 javadoc 的時(shí)候了。在 JDK 的 bin 目錄下你可以找到 javadoc,如果是 Windows 下的 JDK,它的文件名為 javadoc.exe。使用 javdoc 編譯 .java 源文件時(shí),它會(huì )讀出 .java 源文件中的文檔注釋?zhuān)凑找欢ǖ囊巹t與 Java 源程序一起進(jìn)行編譯,生成文檔。
介紹 javadoc 的編譯命令之前,還是先了解一下文檔注釋的格式吧。不過(guò)為了能夠編譯下面提到的若干例子,這里先介紹一條 javadoc 命令:
javadoc -d 文檔存放目錄 -author -version 源文件名.java
這條命令編譯一個(gè)名為 “源文件名.java”的 java 源文件,并將生成的文檔存放在“文檔存放目錄”指定的目錄下,生成的文檔中 index.html 就是文檔的首頁(yè)。-author 和 -version 兩個(gè)選項可以省略。
文檔注釋可以用于對類(lèi)、屬性、方法等進(jìn)行說(shuō)明。寫(xiě)文檔注釋時(shí)除了需要使用 /** .... */ 限定之外,還需要注意注釋內部的一些細節問(wèn)題。
生成的文檔是 HTML 格式,而這些 HTML 格式的標識符并不是 javadoc 加的,而是我們在寫(xiě)注釋的時(shí)候寫(xiě)上去的。比如,需要換行時(shí),不是敲入一個(gè)回車(chē)符,而是寫(xiě)入 <br>,如果要分段,就應該在段前寫(xiě)入 <p>。
因此,格式化文檔,就是在文檔注釋中添加相應的 HTML 標識。
文檔注釋的正文并不是直接復制到輸出文件 (文檔的 HTML 文件),而是讀取每一行后,刪掉前導的 * 號及 * 號以前的空格,再輸入到文檔的。如
| /** * This is first line. <br> ***** This is second line. <br> This is third line. */ |
編譯輸出后的 HTML 源碼則是
| This is first line. <br> This is second line. <br> This is third line. |
前導的 * 號允許連續使用多個(gè),其效果和使用一個(gè) * 號一樣,但多個(gè) * 號前不能有其它字符分隔,否則分隔符及后面的 * 號都將作為文檔的內容。* 號在這里是作為左邊界使用,如上例的第一行和第二行;如果沒(méi)有前導的 * 號,則邊界從第一個(gè)有效字符開(kāi)始,而不包括前面的空格,如上例第三行。
還有一點(diǎn)需要說(shuō)明,文檔注釋只說(shuō)明緊接其后的類(lèi)、屬性或者方法。如下例:
/** comment for class */ public class Test { /** comment for a attribute */ int number; /** comment for a method */ public void myMethod() { ...... } ...... } |
上例中的三處注釋就是分別對類(lèi)、屬性和方法的文檔注釋。它們生成的文檔分別是說(shuō)明緊接其后的類(lèi)、屬性、方法的?!熬o接”二字尤其重要,如果忽略了這一點(diǎn),就很可能造成生成的文檔錯誤。如
import java.lang.*; /** commnet for class */ public class Test { ...... } // 此例為正確的例子 |
這個(gè)文檔注釋將生成正確的文檔。但只需要改變其中兩行的位置,變成下例,就會(huì )出錯:
/** commnet for class */ import java.lang.*; public class Test { ...... } // 此例為錯誤的例子 |
這個(gè)例子只把上例的 import 語(yǔ)句和文檔注釋部分交換了位置,結果卻大不相同——生成的文檔中根本就找不到上述注釋的內容了。原因何在?
“/** commnet for class */”是對 class Test 的說(shuō)明,把它放在“public class Test { ...... }”之前時(shí),其后緊接著(zhù) class Test,符合規則,所以生成的文檔正確。但是把它和“import java.lang.*;”調換了位置后,其后緊接的就是不 class Test 了,而是一個(gè) import 語(yǔ)句。由于文檔注釋只能說(shuō)明類(lèi)、屬性和方法,import 語(yǔ)句不在此列,所以這個(gè)文檔注釋就被當作錯誤說(shuō)明省略掉了。
根據在文檔中顯示的效果,文檔注釋分為三部分。先舉例如下,以便說(shuō)明。
/** * show 方法的簡(jiǎn)述. * <p>show 方法的詳細說(shuō)明第一行<br> * show 方法的詳細說(shuō)明第二行 * @param b true 表示顯示,false 表示隱藏 * @return 沒(méi)有返回值 */ public void show(boolean b) { frame.show(b); } |
第一部分是簡(jiǎn)述。文檔中,對于屬性和方法都是先有一個(gè)列表,然后才在后面一個(gè)一個(gè)的詳細的說(shuō)明。列表中屬性名或者方法名后面那段說(shuō)明就是簡(jiǎn)述。如下圖中被紅框框選的部分:

簡(jiǎn)述部分寫(xiě)在一段文檔注釋的最前面,第一個(gè)點(diǎn)號 (.) 之前 (包括點(diǎn)號)。換句話(huà)說(shuō),就是用第一個(gè)點(diǎn)號分隔文檔注釋?zhuān)笆呛?jiǎn)述,之后是第二部分和第三部分。如上例中的 “* show 方法的簡(jiǎn)述.”。
有時(shí),即使正確地以一個(gè)點(diǎn)號作為分隔,javadoc 仍然會(huì )出錯,把點(diǎn)號后面的部分也做為了第一部分。為了解決這個(gè)問(wèn)題,我們可以使用一個(gè) <p> 標志將第二分部分開(kāi)為下一段,如上例的“* <p>show 方法的詳細說(shuō)明第一行 ....”。除此之外,我們也可以使用 <br> 來(lái)分隔。
第二部分是詳細說(shuō)明部分。該部分對屬性或者方法進(jìn)行詳細的說(shuō)明,在格式上沒(méi)有什么特殊的要求,可以包含若干個(gè)點(diǎn)號。它在文檔中的位置如下圖所示:

這部分文檔在上例中相應的代碼是:
* show 方法的簡(jiǎn)述.
* <p>show 方法的詳細說(shuō)明第一行<br>
* show 方法的詳細說(shuō)明第二行
發(fā)現什么了?對了,簡(jiǎn)述也在其中。這一點(diǎn)要記住了,不要畫(huà)蛇添足——在詳細說(shuō)明部分中再寫(xiě)一次簡(jiǎn)述哦!
第三部分是特殊說(shuō)明部分。這部分包括版本說(shuō)明、參數說(shuō)明、返回值說(shuō)明等。它在文檔中的位置:

第三部分在上例中相應的代碼是
* @param b true 表示顯示,false 表示隱藏
* @return 沒(méi)有返回值
除了 @param 和 @return 之外,還有其它的一些特殊標記,分別用于對類(lèi)、屬性和方法的說(shuō)明……不要推我,我馬上就說(shuō)。
javadoc 標記是插入文檔注釋中的特殊標記,它們用于標識代碼中的特殊引用。javadoc 標記由“@”及其后所跟的標記類(lèi)型和專(zhuān)用注釋引用組成。記住了,三個(gè)部分——@、標記類(lèi)型、專(zhuān)用注釋引用。不過(guò)我寧愿把它分成兩部分:@ 和標記類(lèi)型、專(zhuān)用注釋引用。雖然 @ 和 標記類(lèi)型之間有時(shí)可以用空格符分隔,但是我寧愿始終將它們緊挨著(zhù)寫(xiě),以減少出錯機會(huì )。
javadoc 標記有如下一些:
|
下面詳細說(shuō)明各標記。
@see 的句法有三種:
@see 類(lèi)名
@see #方法名或屬性名
@see 類(lèi)名#方法名或屬性名
類(lèi)名,可以根據需要只寫(xiě)出類(lèi)名 (如 String) 或者寫(xiě)出類(lèi)全名 (如 java.lang.String)。那么什么時(shí)候只需要寫(xiě)出類(lèi)名,什么時(shí)候需要寫(xiě)出類(lèi)全名呢?
如果 java 源文件中的 import 語(yǔ)句包含了的類(lèi),可以只寫(xiě)出類(lèi)名,如果沒(méi)有包含,則需要寫(xiě)出類(lèi)全名。java.lang 也已經(jīng)默認被包含了。這和 javac 編譯 java 源文件時(shí)的規定一樣,所以可以簡(jiǎn)單的用 javac 編譯來(lái)判斷,源程序中 javac 能找到的類(lèi),javadoc 也一定能找到;javac 找不到的類(lèi),javadoc 也找不到,這就需要使用類(lèi)全名了。
方法名或者屬性名,如果是屬性名,則只需要寫(xiě)出屬性名即可;如果是方法名,則需要寫(xiě)出方法名以及參數類(lèi)型,沒(méi)有參數的方法,需要寫(xiě)出一對括號。如
| 成員類(lèi)型 | 成員名稱(chēng)及參數 | @see 句法 |
| 屬性 | number | @see number |
| 屬性 | count | @see count |
| 方法 | count() | @see count() |
| 方法 | show(boolean b) | @see show(boolean) |
| 方法 | main(String[] args) | @see main(String[]) |
有時(shí)也可以偷懶:假如上例中,沒(méi)有 count 這一屬性,那么參考方法 count() 就可以簡(jiǎn)寫(xiě)成 @see count。不過(guò),為了安全起見(jiàn),還是寫(xiě)全 @see count() 比較好。
@see 的第二個(gè)句法和第三個(gè)句法都是轉向方法或者屬性的參考,它們有什么區別呢?
第二個(gè)句法中沒(méi)有指出類(lèi)名,則默認為當前類(lèi)。所以它定義的參考,都轉向本類(lèi)中的屬性或者方法。而第三個(gè)句法中指出了類(lèi)名,則還可以轉向其它類(lèi)的屬性或者方法。
關(guān)于 @see 標記,我們舉個(gè)例說(shuō)明。由于 @see 在對類(lèi)說(shuō)明、對屬性說(shuō)明、對方法說(shuō)明時(shí)用法都一樣,所以這里只以對類(lèi)說(shuō)明為例。
/** * @see String * @see java.lang.StringBuffer * @see #str * @see #str() * @see #main(String[]) * @see Object#toString() */ public class TestJavaDoc { } |
生成的文檔的相關(guān)部分如下圖:

String 和 StringBuffer 都是在 java.lang 包中,由于這個(gè)包是默認導入了的,所以這兩個(gè)類(lèi)可以直接寫(xiě)類(lèi)名,也可以寫(xiě)類(lèi)全名。str、str() 為同名屬性和方法,所以方法名需要用 () 區分。main 是帶參數的方法,所以在 () 中指明了參數類(lèi)型。toString() 雖然在本類(lèi)中也有 (從 Object 繼承的),但我們是想參考 Object 類(lèi)的 toString() 方法,所以使用了 Object#toString()。
奇怪的是,為什么其中只有 str、str() 和 main(String[]) 變成了鏈接呢?那是因為編譯時(shí)沒(méi)有把 java.lang 包或者 Stirng、StringBuffer、Object 三個(gè)類(lèi)的源文件一起加入編譯,所以,生成的文檔沒(méi)有關(guān)于那三個(gè)類(lèi)的信息,也就不可以建立鏈接了。后面講解 javadoc 編譯命令的時(shí)候還會(huì )詳細說(shuō)明。
上例中如果去把類(lèi)中的 str 屬性去掉,那么生成的文檔又會(huì )有什么變化呢?你會(huì )發(fā)現,原來(lái)是 str, str(),而現在變成了 str(), str(),因為 str 屬性已經(jīng)沒(méi)有了,所以 str 也表示方法 str()。
2. 使用 @author、@version 說(shuō)明類(lèi)
這兩個(gè)標記分別用于指明類(lèi)的作者和版本。缺省情況下 javadoc 將其忽略,但命令行開(kāi)關(guān) -author 和 -version 可以修改這個(gè)功能,使其包含的信息被輸出。這兩個(gè)標記的句法如下:
@author 作者名
@version 版本號
其中,@author 可以多次使用,以指明多個(gè)作者,生成的文檔中每個(gè)作者之間使用逗號 (,) 隔開(kāi)。@version 也可以使用多次,只有第一次有效,生成的文檔中只會(huì )顯示第一次使用 @version 指明的版本號。如下例
/** * @author Fancy * @author Bird * @version Version 1.00 * @version Version 2.00 */ public class TestJavaDoc { } |
生成文檔的相關(guān)部分如圖:

從生成文檔的圖示中可以看出,兩個(gè) @author 語(yǔ)句都被編譯,在文檔中生成了作者列表。而兩個(gè) @version 語(yǔ)句中只有第一句被編譯了,只生成了一個(gè)版本號。
從圖上看,作者列表是以逗號分隔的,如果我想分行顯示怎么辦?另外,如果我想顯示兩個(gè)以上的版本號又該怎么辦?
——我們可以將上述兩條 @author 語(yǔ)句合為一句,把兩個(gè) @version 語(yǔ)句也合為一句:
@author Fancy<br>Bird
@version Version 1.00<br>Version 2.00
結果如圖:

我們這樣做即達到了目的,又沒(méi)有破壞規則。@author 之后的作者名和 @version 之后的版本號都可以是用戶(hù)自己定義的任何 HTML 格式,所以我們可以使用 <br> 標記將其分行顯示。同時(shí),在一個(gè) @version 中指明兩個(gè)用 <br> 分隔的版本號,也沒(méi)有破壞只顯示第一個(gè) @version 內容的規則。
3. 使用 @param、@return 和 @exception 說(shuō)明方法
這三個(gè)標記都是只用于方法的。@param 描述方法的參數,@return 描述方法的返回值,@exception 描述方法可能拋出的異常。它們的句法如下:
@param 參數名 參數說(shuō)明
@return 返回值說(shuō)明
@exception 異常類(lèi)名 說(shuō)明
每一個(gè) @param 只能描述方法的一個(gè)參數,所以,如果方法需要多個(gè)參數,就需要多次使用 @param 來(lái)描述。
一個(gè)方法中只能用一個(gè) @return,如果文檔說(shuō)明中列了多個(gè) @return,則 javadoc 編譯時(shí)會(huì )發(fā)出警告,且只有第一個(gè) @return 在生成的文檔中有效。
方法可能拋出的異常應當用 @exception 描述。由于一個(gè)方法可能拋出多個(gè)異常,所以可以有多個(gè) @exception。每個(gè) @exception 后面應有簡(jiǎn)述的異常類(lèi)名,說(shuō)明中應指出拋出異常的原因。需要注意的是,異常類(lèi)名應該根據源文件的 import 語(yǔ)句確定是寫(xiě)出類(lèi)名還是類(lèi)全名。 示例如下:
public class TestJavaDoc { /** * @param n a switch * @param b excrescent parameter * @return true or false * @return excrescent return * @exception java.lang.Exception throw when switch is 1 * @exception NullPointerException throw when parameter n is null */ public boolean fun(Integer n) throws Exception { switch (n.intValue()) { case 0: break; case 1: throw new Exception("Test Only"); default: return false; } return true; } } |
使用 javadoc 編譯生成的文檔相關(guān)部分如下圖:

可以看到,上例中 @param b excrescent parameter 一句是多余的,因為參數只是一個(gè) n,并沒(méi)有一個(gè) b但是 javadoc 編譯時(shí)并沒(méi)有檢查。因此,寫(xiě)文檔注釋時(shí)一定要正確匹配參數表與方法中正式參數表的項目。如果方法參數表中的參數是 a,文檔中卻給出對參數 x 的解釋?zhuān)蛘咴俣喑鲆粋€(gè)參數 i,就會(huì )讓人摸不著(zhù)頭腦了。@exceptin 也是一樣。
上例程序中并沒(méi)有拋出一個(gè) NullPointerException,但是文檔注釋中為什么要寫(xiě)上這么一句呢,難道又是為了演示?這不是為了演示描述多余的異常也能通過(guò)編譯,而是為了說(shuō)明寫(xiě)異常說(shuō)明時(shí)應考運行時(shí) (RunTime) 異常的可能性。上例程序中,如果參數 n 是給的一個(gè)空值 (null),那么程序會(huì )在運行的時(shí)候拋出一個(gè) NullPointerException,因此,在文檔注釋中添加了對 NullPointerException 的說(shuō)明。
上例中的 @return 語(yǔ)句有兩個(gè),但是根據規則,同一個(gè)方法中,只有第一個(gè) @return 有效,其余的會(huì )被 javadoc 忽略。所以生成的文檔中沒(méi)有出現第二個(gè) @return 的描述。
講到這里,該怎么寫(xiě)文檔注釋你應該已經(jīng)清楚了,下面就開(kāi)始講解 javadoc 的常用命令。
運行 javadoc -help 可以看到 javadoc 的用法,這里列舉常用參數如下:
用法:
javadoc [options] [packagenames] [sourcefiles]
選項:
| -public | 僅顯示 public 類(lèi)和成員 | |
| -protected | 顯示 protected/public 類(lèi)和成員 (缺省) | |
| -package | 顯示 package/protected/public 類(lèi)和成員 | |
| -private | 顯示所有類(lèi)和成員 | |
| -d <directory> | 輸出文件的目標目錄 | |
| -version | 包含 @version 段 | |
| -author | 包含 @author 段 | |
| -splitindex | 將索引分為每個(gè)字母對應一個(gè)文件 | |
| -windowtitle <text> | 文檔的瀏覽器窗口標題 |
javadoc 編譯文檔時(shí)可以給定包列表,也可以給出源程序文件列表。例如在 CLASSPATH 下有兩個(gè)包若干類(lèi)如下:
fancy.Editor
fancy.Test
fancy.editor.ECommand
fancy.editor.EDocument
fancy.editor.EView
這里有兩個(gè)包 (fancy 和 fancy.editor) 和 5 個(gè)類(lèi)。那么編譯時(shí) (Windows 環(huán)境) 可以使用如下 javadoc 命令:
javadoc fancy\Test.java fancy\Editor.java fancy\editor\ECommand.java fancy\editor\EDocument.java fancy\editor\EView.java
這是給出 java 源文件作為編譯參數的方法,注意命令中指出的是文件路徑,應該根據實(shí)際情況改變。也可以是給出包名作為編譯參數,如:
javadoc fancy fancy.editor
用瀏覽器打開(kāi)生成文檔的 index.html 文件即可發(fā)現兩種方式編譯結果的不同,如下圖:

用第二條命令生成的文檔被框架分成了三部分:包列表、類(lèi)列表和類(lèi)說(shuō)明。在包列表中選擇了某個(gè)包之后,類(lèi)列表中就會(huì )列出該包中的所有類(lèi);在類(lèi)列表中選擇了某個(gè)類(lèi)之后,類(lèi)說(shuō)明部分就會(huì )顯示出該類(lèi)的詳細文檔。而用第一條命令生成的文檔只有兩部分,類(lèi)列表和類(lèi)說(shuō)明,沒(méi)有包列表。這就是兩種方式生成文檔的最大區別了。
下面再來(lái)細說(shuō)選項。
-public、-protected、-package、-private 四個(gè)選項,只需要任選其一即可。它們指定的顯示類(lèi)成員的程度。它們顯示的成員多少是一個(gè)包含的關(guān)系,如下表:
| -private (顯示所有類(lèi)和成員) | |||||
|
-d 選項允許你定義輸出目錄。如果不用 -d 定義輸出目錄,生成的文檔文件會(huì )放在當前目錄下。-d 選項的用法是
-d 目錄名
目錄名為必填項,也就是說(shuō),如果你使用了 -d 參數,就一定要為它指定一個(gè)目錄。這個(gè)目錄必須已經(jīng)存在了,如果還不存在,請在運行 javadoc 之前創(chuàng )建該目錄。
-version 和 -author 用于控制生成文檔時(shí)是否生成 @version 和 @author 指定的內容。不加這兩個(gè)參數的情況下,生成的文檔中不包含版本和作者信息。
-splitindex 選項將索引分為每個(gè)字母對應一個(gè)文件。默認情況下,索引文件只有一個(gè),且該文件中包含所有索引內容。當然生成文檔內容不多的時(shí)候,這樣做非常合適,但是,如果文檔內容非常多的時(shí)候,這個(gè)索引文件將包含非常多的內容,顯得過(guò)于龐大。使用 -splitindex 會(huì )把索引文件按各索引項的第一個(gè)字母進(jìn)行分類(lèi),每個(gè)字母對應一個(gè)文件。這樣,就減輕了一個(gè)索引文件的負擔。
-windowtitle 選項為文檔指定一個(gè)標題,該標題會(huì )顯示在窗口的標題欄上。如果不指定該標題,而默認的文檔標題為“生成的文檔(無(wú)標題)”。該選項的用法是:
-windowtitle 標題
標題是一串沒(méi)有包含空格的文本,因為空格符是用于分隔各參數的,所以不能包含空格。同 -d 類(lèi)似,如果指定了 -windowtitle 選項,則必須指定標題文本。
到此為止,Java 文檔和 javadoc 就介紹完了。javadoc 真的能讓我們在 Java 注釋上做文章——生成開(kāi)發(fā)文檔。
-=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=- / __________/II\___ 邊城客棧 / _[]_ /____\ /_________/| () |\__\ http://outinn.yeah.com | ____ /-| __ |-\| 歡迎訪(fǎng)問(wèn)邊城客棧 |__|==|___| || |__| -=--=--=- |_||_| =- 邊城狂人, outinn@163.com |
聯(lián)系客服