注釋,J2SE 5.0 (Tiger) 中的新功能,將非常需要的元數(shù)據(jù)工具引入核心 Java 語(yǔ)言。該系列文章分為兩部分,在這第 1 部分中,作者 Brett McLaughlin 解釋了元數(shù)據(jù)如此有用的原因,向您介紹了 Java 語(yǔ)言中的注釋,并研究了 Tiger 的內(nèi)置注釋。<!--START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --> <!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
編程的一個(gè)最新的趨勢(shì),尤其是在 Java 編程方面,是使用 元數(shù)據(jù) 。簡(jiǎn)單地說(shuō),元數(shù)據(jù)就是 關(guān)于 數(shù)據(jù)的數(shù)據(jù)。元數(shù)據(jù)可以用于創(chuàng)建文檔,跟蹤代碼中的依賴性,甚至執(zhí)行基本編譯時(shí)檢查。許多元數(shù)據(jù)工具,如 XDoclet(請(qǐng)參閱 參考資料 ),將這些功能添加到核心 Java 語(yǔ)言中,暫時(shí)成為 Java 編程功能的一部分。
直到可以使用 J2SE 5.0(也叫做 Tiger,現(xiàn)在是第二個(gè) beta 版本),核心 Java 語(yǔ)言才最接近具有 Javadoc 方法的元數(shù)據(jù)工具。您使用特殊的標(biāo)簽集合來(lái)標(biāo)記代碼,并執(zhí)行
javadoc
命令來(lái)將這些標(biāo)簽轉(zhuǎn)化成格式化的 HTML 頁(yè)面,該頁(yè)面說(shuō)明標(biāo)簽所附加到的類。然而,Javadoc 是有缺陷的元數(shù)據(jù)工具,因?yàn)槌松晌臋n之外,您沒(méi)有固定、實(shí)用、標(biāo)準(zhǔn)化的方式來(lái)將數(shù)據(jù)用于其他用途。HTML 代碼經(jīng)常混入到 Javadoc 輸出中這一事實(shí)甚至更進(jìn)一步降低了其用于任何其他目的的價(jià)值。
Tiger 通過(guò)名為 注釋 的新功能將一個(gè)更通用的元數(shù)據(jù)工 具合并到核心 Java 語(yǔ)言中。注釋是可以添加到代碼中的修飾符,可以用于包聲明、類型聲明、構(gòu)造函數(shù)、方法、字段、參數(shù)和變量。Tiger 包含內(nèi)置注釋,還支持您自己編寫的定制注釋。本文將概述元數(shù)據(jù)的優(yōu)點(diǎn)并向您介紹 Tiger 的內(nèi)置注釋。本系列文章的 第 2 部分 將研究定制注釋。我要感謝 O'Reilly Media, Inc.,他們非常慷慨地 允許我在本文中使用我關(guān)于 Tiger 的書籍的“注釋”一章中的代碼示例(請(qǐng)參閱 參考資料 )。
一 般來(lái)說(shuō),元數(shù)據(jù)的好處分為三類:文檔編制、編譯器檢查和代碼分析。代碼級(jí)文檔最常被引用。元數(shù)據(jù)提供了一種有用的方法來(lái)指明方法是否取決于其他方法,它們 是否完整,特定類是否必須引用其他類,等等。這確實(shí)非常有用,但對(duì)于將元數(shù)據(jù)添加到 Java 語(yǔ)言中來(lái)說(shuō),文檔編制可能是 最不 相關(guān)的理由。Javadoc 已經(jīng)提供了非常容易理解和健壯的方法來(lái)文檔化代碼。另外,當(dāng)已經(jīng)存在文檔編制工具,并且在大多數(shù)時(shí)候都工作得很好時(shí),誰(shuí)還要編寫文檔編制工具?
![]() |
|
元數(shù)據(jù)更重要的優(yōu)點(diǎn)是編譯器可以使用它來(lái)執(zhí)行基本的編譯時(shí)檢查。例如,您將在本文后面的 Override 注釋 中 看到 Tiger 引入了一個(gè)這樣的注釋,用于允許您指定一種方法覆蓋超類中的另一種方法。Java 編譯器可以確保在元數(shù)據(jù)中指明的行為實(shí)際發(fā)生在代碼級(jí)別。如果從來(lái)沒(méi)有找出過(guò)這種類型的 bug,這樣做似乎有點(diǎn)傻,但是大多數(shù)年齡很大的 Java 編程老手都曾經(jīng)花費(fèi)至少多個(gè)晚上來(lái)查明他們的代碼為什么不能用。當(dāng)最后認(rèn)識(shí)到方法的參數(shù)有錯(cuò),且該方法實(shí)際上 沒(méi)有 覆蓋超類中的方法時(shí),您可能更感到難受。使用元數(shù)據(jù)的工具有助于輕松地查明這種類型的錯(cuò)誤,從而可以節(jié)省那些晚上來(lái)看長(zhǎng)期進(jìn)行的 Halo 聯(lián)賽。
![]() |
|
可 以證明,任何好的注釋或元數(shù)據(jù)工具的最好功能就是可以使用額外數(shù)據(jù)來(lái)分析代碼。在一個(gè)簡(jiǎn)單的案例中,您可能構(gòu)建代碼目錄,提供必需的輸入類型并指明返回類 型。但是,您可能想,Java 反射具有相同的優(yōu)點(diǎn);畢竟,可以為所有這些信息內(nèi)省代碼。這從表面上看似乎是正確的,但是在實(shí)際中通常不使用。許多時(shí)候,方法作為輸入接受的或者作為輸出 返回的類型實(shí)際上不是該方法想要的類型。例如,參數(shù)類型可能是
Object
,但方法可能僅使用
Integer
。這在好些情況下很容易發(fā)生,比如在方法被覆蓋而超類使用常規(guī)參數(shù)聲明方法時(shí),還有正在進(jìn)行許多序列化的系統(tǒng)中也容易發(fā)生。在這兩種情況中,元數(shù)據(jù)可以指示代碼分析工具,雖然參數(shù)類型是
Object
,但
Integer
才是真正需要的。這類分析非常有用,但也不能夸大它的價(jià)值。
在 更復(fù)雜的情況下,代碼分析工具可以執(zhí)行所有種類的額外任務(wù)。示例 du jour 是 Enterprise JavaBean (EJB) 組件。甚至簡(jiǎn)單 EJB 系統(tǒng)中的依賴性和復(fù)雜性都非常令人吃驚。您具有了 home 接口和遠(yuǎn)程接口,以及本地接口和本地 home 接口,還有一個(gè)實(shí)現(xiàn)類。保持所有這些類同步非常困難。但是,元數(shù)據(jù)可以提供這個(gè)問(wèn)題的解決放案。好的工具(還是要提一下 XDoclet)可以管理所有這些依賴性,并確保無(wú)“代碼級(jí)”連接、但有“邏輯級(jí)”捆綁的類保持同步。元數(shù)據(jù)在這里確實(shí)可以發(fā)揮它的作用。
![]() ![]() |
![]()
|
現(xiàn)在已經(jīng)了解了元數(shù)據(jù)的好處,我將介紹 Tiger 中的注釋。注釋采用“at”標(biāo)記形式 (
@
),后面是注釋名稱。然后在需要數(shù)據(jù)時(shí),通過(guò)
name=value
對(duì)向注釋提供數(shù)據(jù)。每次使用這類表示法時(shí),就是在生成注釋。一段代碼可能會(huì)有 10 個(gè)、50 個(gè)或更多的注釋。不過(guò),您將發(fā)現(xiàn)多個(gè)注釋都可能使用相同的
注釋類型
。類型是實(shí)際使用的結(jié)構(gòu),在特定上下文中,注釋本身是該類型的具體使用(請(qǐng)參閱側(cè)欄
注釋或注釋類型?
)。
![]() |
|
注釋分為三個(gè)基本種類:
-
標(biāo)記注釋
沒(méi)有變量。注釋顯示簡(jiǎn)單,由名稱標(biāo)識(shí),沒(méi)有提供其他數(shù)據(jù)。例如,
@MarkerAnnotation
是標(biāo)記注釋。它不包含數(shù)據(jù),僅有注釋名稱。
-
單一值注釋
與標(biāo)記注釋類似,但提供一段數(shù)據(jù)。因?yàn)閮H提供很少的一點(diǎn)數(shù)據(jù),所以可以使用快捷語(yǔ)法(假設(shè)注釋類型接受此語(yǔ)法):
@SingleValueAnnotation("my data")
。除了@
標(biāo)記外,這應(yīng)該與普通的 Java 方法調(diào)用很像。
-
完整注釋
有多個(gè)數(shù)據(jù)成員。因此,必須使用更完整的語(yǔ)法(注釋不再像普通的 Java 方法):
@FullAnnotation(var1="data value 1", var2="data value 2", var3="data value 3")
。
除了通過(guò)默認(rèn)語(yǔ)法向注釋提供值外,還可以在需要傳送多個(gè)值時(shí)使用名稱-值對(duì)。還可以通過(guò)花括號(hào)為注釋變量提供值數(shù)組。清單 1 顯示了注釋中的值數(shù)組的示例。
清單 1. 在注釋中使用按數(shù)組排列的值
@TODOItems({ // Curly braces indicate an array of values is being supplied |
清單 1 中的示例并沒(méi)有乍一看那樣復(fù)雜。
TODOItems
注釋類型有一個(gè)具有值的變量。這里提供的值比較復(fù)雜,但
TODOItems
的使用實(shí)際與單一值注釋類型相符,只是這里的單一值是數(shù)組而已。該數(shù)組包含三個(gè)
TODO
注釋,其中每個(gè)注釋都是多值的。逗號(hào)分隔每個(gè)注釋內(nèi)的值,以及單個(gè)數(shù)組內(nèi)的值。非常容易,是吧?
但是我講的可能超前了些。
TODOItems
和
TODO
是
定制注釋
, 是本系列文章第 2 部分中的主題。但是我想讓您看到,即使復(fù)雜注釋(清單 1 幾乎是最復(fù)雜的注釋)也不是非常令人害怕的。當(dāng)提到 Java 語(yǔ)言的標(biāo)準(zhǔn)注釋類型時(shí),將很少看到如此復(fù)雜的情況。正如將在下面三個(gè)部分了解到的,Tiger 的基本注釋類型的使用都極其簡(jiǎn)單。
![]() ![]() |
![]()
|
Tiger 的第一個(gè)內(nèi)置注釋類型是
Override
。
Override
應(yīng)該僅用于方法(不用于類、包聲明或其他構(gòu)造)。它指明注釋的方法將覆蓋超類中的方法。清單 2 顯示了簡(jiǎn)單的示例。
清單 2. 操作中的 Override 注釋
package com.oreilly.tiger.ch06; |
清單 2 應(yīng)該很容易理解。
@Override
注釋對(duì)兩個(gè)方法進(jìn)行了注釋 —
toString()
和
hashCode()
,來(lái)指明它們覆蓋
OverrideTester
類的超類 (
java.lang.Object
) 中的方法的版本。開始這可能看起來(lái)沒(méi)什么作用,但它實(shí)際上是非常好的功能。如果不覆蓋這些方法,根本
無(wú)法
編譯此類。該注釋還確保當(dāng)您將
toString()
弄亂時(shí),至少還有某種指示,即應(yīng)該確保
hashCode()
仍舊匹配。
當(dāng)編碼到很晚且輸錯(cuò)了某些東西時(shí),此注釋類型真的可以發(fā)揮很大的作用,如清單 3 中所示。
清單 3. 使 Override 注釋捕獲打字稿
package com.oreilly.tiger.ch06; |
在清單 3 中,
hashCode()
錯(cuò)誤地輸入為
hasCode()
。注釋指明
hasCode()
應(yīng)該覆蓋方法。但是在編譯中,
javac
將發(fā)現(xiàn)超類 (
java.lang.Object
) 沒(méi)有名為
hasCode()
的方法可以覆蓋。因此,編譯器將報(bào)錯(cuò),如圖 1 中所示。
圖 1. 來(lái)自 Override 注釋的編譯器警告
![]() |
|
這個(gè)便捷的小功能將幫助快速捕獲打字稿。
![]() ![]() |
![]()
|
下一個(gè)標(biāo)準(zhǔn)注釋類型是
Deprecated
。與
Override
一樣,
Deprecated
是標(biāo)記注釋。正如您可能期望的,可以使用
Deprecated
來(lái)對(duì)不應(yīng)再使用的方法進(jìn)行注釋。與
Override
不一樣的是,
Deprecated
應(yīng)該與正在聲明為過(guò)時(shí)的方法放在同一行中(為什么這樣?說(shuō)實(shí)話我也不知道),如清單 4 中所示。
清單 4. 使用 Deprecated 注釋
package com.oreilly.tiger.ch06; |
單獨(dú)編譯此類時(shí),不會(huì)發(fā)生任何不同。但是如果通過(guò)覆蓋或調(diào)用來(lái)使用聲明為過(guò)時(shí)的方法,編譯器將處理注釋,發(fā)現(xiàn)不應(yīng)該使用該方法,并發(fā)出錯(cuò)誤消息,如圖 2 中所示。
圖 2. 來(lái)自 Deprecated 注釋的編譯器警告
注意需要開啟編譯器警告,就像是必須向 Java 編譯器指明想要普通的聲明為過(guò)時(shí)警告。可以使用下列兩個(gè)標(biāo)記之一和
javac
命令:
-deprecated
或新的
-Xlint:deprecated
標(biāo)記。
![]() ![]() |
![]()
|
從 Tiger “免費(fèi)”獲得的最后一個(gè)注釋類型是
SuppressWarnings
。發(fā)現(xiàn)該類型的作用應(yīng)該不難,但是
為什么
該注釋類型如此重要通常不是很明顯。它實(shí)際上是 Tiger 的所有新功能的副功能。例如,以泛型為例;泛型使所有種類的新類型安全操作成為可能,特別是當(dāng)涉及 Java 集合時(shí)。然而,因?yàn)榉盒停?dāng)使用集合而
沒(méi)有
類型安全時(shí),編譯器將拋出警告。這對(duì)于針對(duì) Tiger 的代碼有幫助,但它使得為 Java 1.4.x 或更早版本編寫代碼非常麻煩。將不斷地收到關(guān)于根本無(wú)關(guān)的事情的警告。如何才能使編譯器不給您增添麻煩?
SupressWarnings
可以解決這個(gè)問(wèn)題。
SupressWarnings
與
Override
和
Deprecated
不同,
是
具有變量的 — 所以您將單一注釋類型與該變量一起使用。可以以值數(shù)組來(lái)提供變量,其中每個(gè)值指明要阻止的一種特定警告類型。請(qǐng)看清單 5 中的示例,這是 Tiger 中通常會(huì)產(chǎn)生錯(cuò)誤的一些代碼。
public void nonGenericsMethod() { |
圖 3 顯示了清單 5 中代碼的編譯結(jié)果。
圖 3. 來(lái)自非標(biāo)準(zhǔn)代碼的編譯器警告
清單 6 通過(guò)使用
SuppressWarnings
注釋消除了這種問(wèn)題。
@SuppressWarings(value={"unchecked"}) |
非常簡(jiǎn)單,是吧??jī)H需要找到警告類型(圖 3 中顯示為“unchecked”),并將其傳送到
SuppressWarnings
中。
SuppressWarnings
中變量的值采用數(shù)組,使您可以在同一注釋中阻止多個(gè)警告。例如,
@SuppressWarnings(value={"unchecked", "fallthrough"})
使用兩個(gè)值的數(shù)組。此功能為處理錯(cuò)誤提供了非常靈活的方法,無(wú)需進(jìn)行大量的工作。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
