<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Java Votary

      BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      48 隨筆 :: 1 文章 :: 80 評(píng)論 :: 0 Trackbacks

    Tiger 中的注釋,第 2 部分: 定制注釋

    Write your own annotations in Java 5

    developerWorks
    文檔選項(xiàng)
    將此頁(yè)作為電子郵件發(fā)送

    將此頁(yè)作為電子郵件發(fā)送

    未顯示需要 JavaScript 的文檔選項(xiàng)


    對(duì)此頁(yè)的評(píng)價(jià)

    幫助我們改進(jìn)這些內(nèi)容


    級(jí)別: 初級(jí)

    Brett McLaughlin, 作者/編者, O'Reilly Media, Inc

    2004 年 9 月 01 日

    本系列文章的 第 1 部分介紹了注釋 —— J2SE 5.0 中新的元數(shù)據(jù)工具,并重點(diǎn)討論了 Tiger 的基本內(nèi)置注釋。一個(gè)更強(qiáng)大的相關(guān)特性是支持編寫自己的注釋。本文中,Brett McLauglin 說(shuō)明了如何創(chuàng)建定制注釋,如何用自己的注釋注解文檔,并進(jìn)一步定制代碼。

    本系列的第一篇文章 介紹了什么是元數(shù)據(jù),元數(shù)據(jù)的重要性,以及如何使用 J2SE 5.0(也叫做 Tiger)的基本內(nèi)置注釋。如果習(xí)慣了這些概念,您可能已經(jīng)在想,Java 5 提供的三種標(biāo)準(zhǔn)注釋也并不是特別健壯,能使用的只有 DeprecatedSuppressWarningsOverride 而已。所幸的是,Tiger 還允許定義自己的注釋類型。在本文中,我將通過(guò)一些示例引導(dǎo)您掌握這個(gè)相對(duì)簡(jiǎn)單的過(guò)程。您還將了解如何對(duì)自己的注釋進(jìn)行注解,以及這樣做的一些好處。我要 感謝 O'Reilly Media, Inc.,他們非常慷慨地允許我在本文中使用我關(guān)于 Tiger 的書籍的“注釋”一章中的代碼示例(請(qǐng)參閱 參考資料)。

    定義自己的注釋類型


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

    @interface 聲明


    定義新的注釋類型與創(chuàng)建接口有很多類似之處,只不過(guò) interface 關(guān)鍵字之前要有一個(gè) @ 符號(hào)。清單 1 中給出的是一個(gè)最簡(jiǎn)單的注釋類型的示例:
    清單 1. 非常簡(jiǎn)單的注釋類型

    package com.oreilly.tiger.ch06;

    /**
    * Marker annotation to indicate that a method or class
    * is still in progress.
    */
    public @interface InProgress { }

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

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

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

    不要漏掉本系列的另一部分

    一定要閱讀本系列文章的“ 第 1 部分”,其中介紹了 Java 5.0 中的注釋。

    添加成員


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

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

    清單 3. 向注釋類型添加成員

    package com.oreilly.tiger.ch06;

    /**
    * Annotation type to indicate a task still needs to be
    * completed.
    */
    public @interface TODO {
    String value();
    }

    盡管清單 3 看起來(lái)很奇怪,但這是注釋類型所要求的格式。清單 3 定義了一個(gè)名為 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
    }

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

    清單 5. 清單 4 的“加長(zhǎng)”版

    @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)然作為編碼人員,我們都不愿意跟這種“加長(zhǎng)”版攪在一起。不過(guò)要注意,只有當(dāng)注釋類型只有 一個(gè) 成員變量,而且變量名為 value 時(shí),才能使用簡(jiǎn)寫形式。如果不符合這個(gè)條件,那么就無(wú)法利用這種特性。

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


    迄 今為止,您已經(jīng)有了一個(gè)很好的起點(diǎn),但是要做得完美,還有很長(zhǎng)的一段路要走。您可能已經(jīng)想到,下一步就要為注釋設(shè)置某個(gè)默認(rèn)值。如果您希望用戶指定某些 值,但是只有這些值與默認(rèn)值不同的時(shí)候才需要指定其他的值,那么設(shè)置默認(rèn)值就是一種很好的辦法。清單 6 用另一個(gè)定制注釋 —— 來(lái)自 清單 4TODO 注釋類型的一個(gè)全功能版本,示范了這個(gè)概念及其實(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 注釋類型中添加了幾個(gè)新的變量。因?yàn)樵撟⑨岊愋偷某蓡T變量不是一個(gè),所以將一個(gè)變量命名為 value 沒(méi)有任何意義。只要成員變量多于一個(gè),就應(yīng)該盡可能準(zhǔn)確地為其命名。因?yàn)椴豢赡軓? 清單 5所示的簡(jiǎn)寫形式中獲益,所以您需要?jiǎng)?chuàng)建雖然稍微有點(diǎn)冗長(zhǎng),但是更容易理解的注釋類型。

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

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



    回頁(yè)首


    對(duì)注釋的注釋


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

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

    指定目標(biāo)


    最明顯的元注釋就是允許何種程序元素具有定義的注釋類型。毫不奇怪,這種元注釋被稱為 Target 。但是在了解如何使用 Target 之前,您還需要認(rèn)識(shí)另一個(gè)類,該類被稱為 ElementType ,它實(shí)際上是一個(gè)枚舉。這個(gè)枚舉定義了注釋類型可應(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)(通過(guò)后面的注解)。使用 Target 元注釋時(shí),至少要提供這些枚舉值中的一個(gè)并指出注釋的注釋可以應(yīng)用的程序元素。清單 10 說(shuō)明了 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ù)和其他注釋類型。這樣有助于避免他人誤用您的注釋類型(或者最好的地方是, 您自己也不會(huì)因?yàn)槠v而誤用它)。

    設(shè)置保持性


    下一個(gè)要用到的元注釋是 Retention 。這個(gè)元注釋和 Java 編譯器處理注釋的注釋類型的方式有關(guān)。編譯器有幾種不同選擇:
    • 將注釋保留在編譯后的類文件中,并在第一次加載類時(shí)讀取它。
    • 將注釋保留在編譯后的類文件中,但是在運(yùn)行時(shí)忽略它。
    • 按照規(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 所示的枚舉值中的一個(gè)作為惟一的參數(shù)。可以將該元注釋用于您的注釋,如清單 12 所示:

    清單 12. 使用 Retention 元注釋

    @Retention(RetentionPolicy.SOURCE)
    public @interface SuppressWarnings {
    // annotation type body
    }

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

    添加公共文檔


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

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

    設(shè)置繼承


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

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



    回頁(yè)首


    結(jié)束語(yǔ)


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

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



    回頁(yè)首


    參考資料

    • 您可以參閱本文在 developerWorks 全球站點(diǎn)上的 英文原文

    • 不要遺漏“ Tiger 中的注釋,第 2 部分”,即本系列文章的第 2 部分,研究了定制注釋。



    • 開放源代碼 XDoclet代碼生成引擎支持面向?qū)傩缘?Java 語(yǔ)言編程。



    • JSR 175,將元數(shù)據(jù)工具合并到 Java 語(yǔ)言中的規(guī)范,處于 Java Community Process 的提議最終草案狀態(tài)。



    • 訪問(wèn) Sun 的主頁(yè),獲取 J2SE 5.0 的所有信息



    • 可以 下載 Tiger并自己試用。



    • John Zukowski 的系列文章 Taming Tiger 以實(shí)用的基于技巧的形式講述了 Java 5.0 的新功能。



    • 由 Brett McLaughlin 和 David Flanagan 撰寫的 Java 1.5 Tiger: A Developer's Notebook 一書 (O'Reilly & Associates; 2004),以代碼為中心、開發(fā)人員友好的形式,講述了幾乎所有的 Tiger 的最新功能 — 包括注釋。



    • developerWorksJava 技術(shù)專區(qū) 可以找到數(shù)百篇有關(guān) Java 技術(shù)的參考資料。



    • 訪問(wèn) Developer Bookstore,獲得技術(shù)書籍的完整列表,其中包括數(shù)百本 Java 相關(guān)主題的書籍。



    • 是否對(duì)無(wú)需通常的高成本入口點(diǎn)(entry point)或短期評(píng)估許可證的 IBM 測(cè)試產(chǎn)品感興趣? developerWorks Subscription為 WebSphere?、DB2?、Lotus?、Rational? 和 Tivoli? 產(chǎn)品提供了低成本的 12 個(gè)月單用戶許可證,包括基于 Eclipse 的 WebSphere Studio? IDE,用于開發(fā)、測(cè)試、評(píng)估和展示您的應(yīng)用程序。




    回頁(yè)首


    關(guān)于作者

    作者照片

    Brett McLaughlin 從 Logo 時(shí)代(還記得那個(gè)小三角嗎?)就開始從事計(jì)算機(jī)工作。在最近幾年里,他已經(jīng)成為 Java 和 XML 社區(qū)最知名的作者和程序員之一。他曾經(jīng)在 Nextel Communications 實(shí)現(xiàn)復(fù)雜的企業(yè)系統(tǒng),在 Lutris Technologies 編寫應(yīng)用程序服務(wù)器,目前在為 O'Reilly Media, Inc 撰寫和編輯 書籍

    posted on 2005-12-13 23:28 Dion 閱讀(841) 評(píng)論(0)  編輯  收藏 所屬分類: Java
    主站蜘蛛池模板: 亚洲第一视频在线观看免费| 国产亚洲视频在线| 91麻豆国产自产在线观看亚洲| 国产日韩亚洲大尺度高清| 处破痛哭A√18成年片免费| 免费播放一区二区三区| 久久精品国产亚洲AV| 亚洲午夜精品一区二区公牛电影院| 成年免费大片黄在线观看岛国| 亚洲日本人成中文字幕| 亚洲电影一区二区三区| 色噜噜AV亚洲色一区二区| 国产一区二区三区免费在线观看| 麻豆69堂免费视频| 国产精品亚洲专区在线观看 | 国产成A人亚洲精V品无码性色| 99久久久国产精品免费牛牛四川 | 每天更新的免费av片在线观看 | 曰批全过程免费视频网址| a级片免费在线观看| 久香草视频在线观看免费| 国产亚洲男人的天堂在线观看| 国产午夜亚洲不卡| 亚洲av日韩av欧v在线天堂| 日日操夜夜操免费视频| 在线jlzzjlzz免费播放| 德国女人一级毛片免费| 成人黄18免费视频| 毛片免费视频播放| 久草免费在线观看视频| 无码av免费毛片一区二区| 亚欧免费视频一区二区三区| 91免费人成网站在线观看18| 亚洲成人免费电影| 在线看片免费不卡人成视频| av无码国产在线看免费网站| 国产三级在线观看免费| 暖暖日本免费在线视频| 免费大香伊蕉在人线国产| 亚洲AV成人精品日韩一区18p| 国产高清免费视频|