国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
Tiger 中的注釋 第2部分:定制注釋

定義自己的注釋類型


通過添加了一個小小的語法(Tiger 添加了大量的語法結(jié)構(gòu)),Java 語言支持一種新的類型 —— 注釋類型(annotation type)。注釋類型看起來很像普通的類,但是有一些特有的性質(zhì)。最明顯的一點(diǎn)是,可以在類中以符號( @ )的形式注釋其他 Java 代碼。我將一步一步地介紹這個過程。

@interface 聲明


定義新的注釋類型與創(chuàng)建接口有很多類似之處,只不過 interface 關(guān)鍵字之前要有一個 @ 符號。清單 1 中給出的是一個最簡單的注釋類型的示例:
清單 1. 非常簡單的注釋類型
package com.oreilly.tiger.ch06;/** * Marker annotation to indicate that a method or class *   is still in progress. */public @interface InProgress { }

清單 1 的含義非常明顯。如果編譯這個注釋類型,并確信其位于類路徑中,那么您就可以在自己的源代碼方法中使用它,以指出某個方法或類仍在處理中,如清單 2 所示:

清單 2. 使用定制的注釋類型
@com.oreilly.tiger.ch06.InProgresspublic void calculateInterest(float amount, float rate) {  // Need to finish this method later}

清單 1 所示注釋類型的使用方法和內(nèi)置注釋類型的使用方法完全相同,只不過要同時使用名稱和所在的包來指示定制注釋。當(dāng)然,一般的 Java 規(guī)則仍然適用,您可以導(dǎo)入該注釋類型,直接使用 @InProgress 引用它。

添加成員


上面所示的基本用法還遠(yuǎn)遠(yuǎn)不夠健壯。您一定還記得“第 1 部分”中曾經(jīng)提到的,注釋類型可以有成員變量(請參閱 參考資料)。這一點(diǎn)非常有用,尤其是準(zhǔn)備將注釋作為更加復(fù)雜的元數(shù)據(jù),而不僅僅將它作為原始文檔使用的時候。代碼分析工具喜歡加工大量的信息,定制注釋可以提供這類信息。

注釋類型中的數(shù)據(jù)成員被設(shè)置成使用有限的信息進(jìn)行工作。定義數(shù)據(jù)成員后不需要分別定義訪問和修改的方法。相反,只需要定義一個方法,以成員的名稱命名它。數(shù)據(jù)類型應(yīng)該是該方法返回值的類型。清單 3 是一個具體的示例,它澄清了一些比較含糊的要求:

清單 3. 向注釋類型添加成員
package com.oreilly.tiger.ch06;/** * Annotation type to indicate a task still needs to be *   completed. */public @interface TODO {  String value();}

盡管清單 3 看起來很奇怪,但這是注釋類型所要求的格式。清單 3 定義了一個名為 value 的字符串,該注釋類型能夠接受它。然后,就可以像清單 4 中那樣使用注釋類型:

清單 4. 使用帶有成員值的注釋類型
@com.oreilly.tiger.ch06.InProgress@TODO("Figure out the amount of interest per month")public void calculateInterest(float amount, float rate) {  // Need to finish this method later}

這里同樣沒有多少花樣。清單 4 假設(shè)已經(jīng)引入了 com.oreilly.tiger.ch06.TODO ,因此源代碼中的注釋 需要包名作前綴。此外,需要注意的是,清單 4 中采用了簡寫的方法:將值 ("Figure out the amount of interest per month") 直接提供給注釋,沒有指定成員變量名。清單 4 和清單 5 是等價的,后者沒有采用簡寫形式:

清單 5. 清單 4 的“加長”版
@com.oreilly.tiger.ch06.InProgress@TODO(value="Figure out the amount of interest per month")public void calculateInterest(float amount, float rate) {  // Need to finish this method later}

當(dāng)然作為編碼人員,我們都不愿意跟這種“加長”版攪在一起。不過要注意,只有當(dāng)注釋類型只有 一個 成員變量,而且變量名為 value 時,才能使用簡寫形式。如果不符合這個條件,那么就無法利用這種特性。

設(shè)置默認(rèn)值


迄今為止,您已經(jīng)有了一個很好的起點(diǎn),但是要做得完美,還有很長的一段路要走。您可能已經(jīng)想到,下一步就要為注釋設(shè)置某個默認(rèn)值。如果您希望用戶指定某些值,但是只有這些值與默認(rèn)值不同的時候才需要指定其他的值,那么設(shè)置默認(rèn)值就是一種很好的辦法。清單 6 用另一個定制注釋 —— 來自 清單 4TODO 注釋類型的一個全功能版本,示范了這個概念及其實(shí)現(xiàn):
清單 6. 帶有默認(rèn)值的注釋類型
package com.oreilly.tiger.ch06;public @interface GroupTODO {  public enum Severity { CRITICAL, IMPORTANT, TRIVIAL, DOCUMENTATION };  Severity severity()         default Severity.IMPORTANT;  String item();  String assignedTo();  String dateAssigned();}      

清單 6 中的 GroupTODO 注釋類型中添加了幾個新的變量。因?yàn)樵撟⑨岊愋偷某蓡T變量不是一個,所以將一個變量命名為 value 沒有任何意義。只要成員變量多于一個,就應(yīng)該盡可能準(zhǔn)確地為其命名。因?yàn)椴豢赡軓?清單 5所示的簡寫形式中獲益,所以您需要創(chuàng)建雖然稍微有點(diǎn)冗長,但是更容易理解的注釋類型。

清單 6 中出現(xiàn)的另一個新特性是注釋類型定義了自己的枚舉(枚舉,即 enumeration,通常也稱為 enums,是 Java 5 的另一個新特性。它并沒有多么地不同凡響,對注釋類型更是如此)。然后,清單 6 使用新定義的枚舉作為一個成員變量的類型。

最后,再回到我們的主題 —— 默認(rèn)值。建立默認(rèn)值的過程非?,嵥?,需要在成員聲明的后面添加關(guān)鍵字 default ,然后提供默認(rèn)值。正如您所料,默認(rèn)值的類型必須與成員變量聲明的類型完全相同。同樣,這也不是什么火箭科學(xué),只不過是詞法上的變異。清單 7 給出了一個具體應(yīng)用中的 GroupTODO 注釋,其中 沒有 指定 severity 成員:

清單 7. 使用默認(rèn)值
  @com.oreilly.tiger.ch06.InProgress  @GroupTODO(    item="Figure out the amount of interest per month",    assignedTo="Brett McLaughlin",    dateAssigned="08/04/2004"  )  public  void calculateInterest(float amount, float rate) {    // Need to finish this method later  }

清單 8 中使用了同一個注釋,但這一次給出了 severity 的值:

清單 8. 改寫默認(rèn)值
  @com.oreilly.tiger.ch06.InProgress  @GroupTODO(    severity=GroupTODO.Severity.DOCUMENTATION,    item="Need to explain how this rather unusual method works",    assignedTo="Jon Stevens",    dateAssigned="07/30/2004"  )  public  void reallyConfusingMethod(int codePoint) {    // Really weird code implementation  }




對注釋的注釋


結(jié)束關(guān)于注釋的討論之前(至少在本系列文章中),我想簡要地討論一下注釋的注釋。第 1 部分中所接觸的預(yù)定義注釋類型都有預(yù)定義的目的。但是在編寫自己的注釋類型時,注釋類型的目的并不總是顯而易見的。除了基本的文檔外,可能還要針對某個特定的成員類型或者一組成員類型編寫類型。這就要求您為注釋類型提供某種元數(shù)據(jù),以便編譯器保證按照預(yù)期的目的使用注釋。

當(dāng)然,首先想到的就是 Java 語言選擇的元數(shù)據(jù)形式 —— 注釋。您可以使用 4 種預(yù)定義的注釋類型(稱為 元注釋)對您的注釋進(jìn)行注釋。我將對這 4 種類型分別進(jìn)行介紹。

指定目標(biāo)


最明顯的元注釋就是允許何種程序元素具有定義的注釋類型。毫不奇怪,這種元注釋被稱為 Target 。但是在了解如何使用 Target 之前,您還需要認(rèn)識另一個類,該類被稱為 ElementType ,它實(shí)際上是一個枚舉。這個枚舉定義了注釋類型可應(yīng)用的不同程序元素。清單 9 給出了完整的 ElementType 枚舉:
清單 9. ElementType 枚舉
package java.lang.annotation;public enum ElementType {  TYPE,			// Class, interface, or enum (but not annotation)  FIELD,		// Field (including enumerated values)  METHOD,		// Method (does not include constructors)  PARAMETER,		// Method parameter  CONSTRUCTOR,		// Constructor  LOCAL_VARIABLE,	// Local variable or catch clause  ANNOTATION_TYPE,	// Annotation Types (meta-annotations)  PACKAGE		// Java package}

清單 9 中的枚舉值意義很明確,您自己可以分析其應(yīng)用的目標(biāo)(通過后面的注解)。使用 Target 元注釋時,至少要提供這些枚舉值中的一個并指出注釋的注釋可以應(yīng)用的程序元素。清單 10 說明了 Target 的用法:

清單 10. 使用 Target 元注釋
package com.oreilly.tiger.ch06;import java.lang.annotation.ElementType;import java.lang.annotation.Target;/** * Annotation type to indicate a task still needs to be completed */@Target({ElementType.TYPE,         ElementType.METHOD,         ElementType.CONSTRUCTOR,         ElementType.ANNOTATION_TYPE})public @interface TODO {  String value();}

現(xiàn)在,Java 編譯器將把 TODO 應(yīng)用于類型、方法、構(gòu)造函數(shù)和其他注釋類型。這樣有助于避免他人誤用您的注釋類型(或者最好的地方是, 您自己也不會因?yàn)槠v而誤用它)。

設(shè)置保持性


下一個要用到的元注釋是 Retention 。這個元注釋和 Java 編譯器處理注釋的注釋類型的方式有關(guān)。編譯器有幾種不同選擇:
  • 將注釋保留在編譯后的類文件中,并在第一次加載類時讀取它。
  • 將注釋保留在編譯后的類文件中,但是在運(yùn)行時忽略它。
  • 按照規(guī)定使用注釋,但是并不將它保留到編譯后的類文件中。

這三種選項(xiàng)用 java.lang.annotation.RetentionPolicy 枚舉表示,如清單 11 所示:

清單 11. RetentionPolicy 枚舉
package java.lang.annotation;public enum RetentionPolicy {  SOURCE,		// Annotation is discarded by the compiler  CLASS,		// Annotation is stored in the class file, but ignored by the VM  RUNTIME		// Annotation is stored in the class file and read by the VM}

現(xiàn)在可以看出, Retention 元注釋類型使用清單 11 所示的枚舉值中的一個作為惟一的參數(shù)??梢詫⒃撛⑨層糜谀淖⑨專缜鍐?12 所示:

清單 12. 使用 Retention 元注釋
@Retention(RetentionPolicy.SOURCE)public @interface SuppressWarnings {  // annotation type body}

如清單 12 所示,這里可以使用簡寫形式,因?yàn)?Retention 只有一個成員變量。如果要將保持性設(shè)為 RetentionPolicy.CLASS ,那么什么也不需要做,因?yàn)檫@就是默認(rèn)行為。

添加公共文檔


下一個元注釋是 Documented 。這個元注釋也非常容易理解,部分原因是 Documented 是一個標(biāo)記注釋。您應(yīng)該還記得第 1 部分中曾經(jīng)提到,標(biāo)記注釋沒有成員變量。 Documented 表示注釋應(yīng)該出現(xiàn)在類的 Javadoc 中。在默認(rèn)情況下,注釋 包括在 Javadoc 中,如果花費(fèi)大量時間注釋一個類、詳細(xì)說明未完成的工作、正確完成了什么或者描述行為,那么您應(yīng)該記住這一點(diǎn)。

清單 13 說明了 Documented 元注釋的用法:

清單 13. 使用 Documented 元注釋
package com.oreilly.tiger.ch06;import java.lang.annotation.Documented;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;/** * Marker annotation to indicate that a method or class *   is still in progress. */        @Documented@Retention(RetentionPolicy.RUNTIME)public @interface InProgress { }      

Documented 的一個實(shí)用技巧是保持性策略。注意,清單 13 中規(guī)定注釋的保持性(retention)是 RUNTIME ,這是使用 Documented 注釋類型所 必需的。Javadoc 使用虛擬機(jī)從其類文件(而非源文件)中加載信息。確保 VM 從這些類文件中獲得生成 Javadoc 所需信息的惟一方法是將保持性規(guī)定為 RetentionPolicy.RUNTIME 。這樣,注釋就會保留在編譯后的類文件中 并且由虛擬機(jī)加載,然后 Javadoc 可以從中抽取出來添加到類的 HTML 文檔中。

設(shè)置繼承


最后一個元注釋 Inherited ,可能是最復(fù)雜、使用最少、也最容易造成混淆的一個。這就是說,我們簡單地看一看就可以了。

首先考慮這樣一種情況:假設(shè)您通過定制的 InProgress 注釋標(biāo)記一個類正在開發(fā)之中,這完全沒有問題,對吧?這些信息還會出現(xiàn)在 Javadoc 中,只要您正確地應(yīng)用了 Documented 元注釋?,F(xiàn)在,假設(shè)您要編寫一個新類,擴(kuò)展那個還在開發(fā)之中的類,也不難,是不是?但是要記住,那個超類還在開發(fā)之中。如果您使用子類,或者查看它的文檔,根本沒有線索表明還有什么地方?jīng)]有完成。您本來希望看到 InProgress 注釋被帶到子類中 —— 因?yàn)檫@是 繼承 的 —— 但情況并非如此。您必須使用 Inherited 元注釋說明所期望的行為,如清單 14 所示:

清單 14. 使用 Inherited 元注釋
package com.oreilly.tiger.ch06;import java.lang.annotation.Documented;import java.lang.annotation.Inherited;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;/** * Marker annotation to indicate that a method or class *   is still in progress. */@Documented        @Inherited@Retention(RetentionPolicy.RUNTIME)public @interface InProgress { }      

添加 @Inherited 后,您將看到 InProgress 出現(xiàn)在注釋類的子類中。當(dāng)然,您并不希望所有的注釋類型都具有這種行為(因此默認(rèn)值是 繼承的)。比如, TODO 注釋就不會(也不應(yīng)該)被傳播。但是對于這里示范的情況, Inherited 可能非常有用。





結(jié)束語


現(xiàn)在,您也許已經(jīng)準(zhǔn)備回到 Java 世界為所有的事物編寫文檔和注釋了。這不禁令我回想起人們了解 Javadoc 之后發(fā)生的事情。我們都陷入了文檔過濫的泥潭,直到有人認(rèn)識到最好使用 Javadoc 來理清容易混淆的類或者方法。無論用 Javadoc 做了多少文章,也沒有人會去看那些易于理解的 getXXX()setXXX() 方法。

注釋也可能出現(xiàn)同樣的趨勢,雖然不一定到那種程度。經(jīng)常甚至頻繁地使用標(biāo)準(zhǔn)注釋類型是一種較好的做法。所有的 Java 5 編譯器都支持它們,它們的行為也很容易理解。但是,如果要使用定制注釋和元注釋,那么就很難保證花費(fèi)很大力氣創(chuàng)建的那些類型在您的開發(fā)環(huán)境之外還有什么意義。因此要慎重。在合理的情況下使用注釋,不要荒謬使用。無論如何,注釋都是一種很好的工具,可以在開發(fā)過程中提供真正的幫助。

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報(bào)
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Tiger系列四:Annotation第二部分:定制Annotation
java.lang和java.lang.annotation中實(shí)現(xiàn)Annotation的類小結(jié)
深入理解Java:注解(Annotation)自定義注解入門
元數(shù)據(jù)(注釋)- J2SE5之5
Java Annotation詳解
Java核心技術(shù)點(diǎn)之注解
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服