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

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

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

    隨筆 - 312, 文章 - 14, 評論 - 1393, 引用 - 0
    數據加載中……

    J2SE5.0中最有趣的新特性:注釋(annotation)

    本文為原創,如需轉載,請注明作者和出處,謝謝!

    本文曾發表于IT168:http://tech.it168.com/j/e/2006-09-29/200609291054707.shtml

        本文將向你介紹J2SE5.0中的新特性之一:注釋。本文將從什么是注釋;J2SE5.0中預定義的注釋;如何自定義注釋;如何對注釋進行注釋以及如何在程序中讀取注釋5個方面進行討論。

    一、什么是注釋

        說起注釋,得先提一提什么是元數據(metadata)。所謂元數據就是數據的數據。也就是說,元數據是描述數據的。就象數據表中的字段一樣,每個字段描述了這個字段下的數據的含義。而J2SE5.0中提供的注釋就是java源代碼的元數據,也就是說注釋是描述java源代碼的。在J2SE5.0中可以自定義注釋。使用時在@后面跟注釋的名字。

    二、J2SE5.0中預定義的注釋

        J2SE5.0java.lang包中預定義了三個注釋。它們是OverrideDeprecatedSuppressWarnings。下面分別解釋它們的含義。

        Override

        這個注釋的作用是標識某一個方法是否覆蓋了它的父類的方法。那么為什么要標識呢?讓我們來看看如果不用Override標識會發生什么事情。

        假設有兩個類Class1ParentClass1,用Class1中的myMethod1方法覆蓋ParentClass1中的myMethod1方法。


     class ParentClass1
     {
        
    public void myMethod1() {}
     }

     
    class Class1 extends ParentClass1
     {
        
    public void myMethod2() {}        
     }

     建立Class1的實例,并且調用myMethod1方法

        ParentClass1 c1 = new Class1();

        c1.myMethod1();

        以上的代碼可以正常編譯通過和運行。但是在寫Class1的代碼時,誤將myMethod1寫成了myMethod2,然而在調用時,myMethod1并未被覆蓋。因此,c1.myMethod1()調用的還是ParentClass1myMethod1方法。更不幸的是,程序員并未意識到這一點。因此,這可能會產生bug

        如果我們使用Override來修飾Class1中的myMethod1方法,當myMethod1被誤寫成別的方法時,編譯器就會報錯。因此,就可以避免這類錯誤。

    class Class1 extends ParentClass1
    {
        @Override   
    // 編譯器產生一個錯誤
        public void myMethod2() {}        
    }


        以上代碼編譯不能通過,被Override注釋的方法必須在父類中存在同樣的方法程序才能編譯通過。也就是說只有下面的代碼才能正確編譯。

    class Class1 extends ParentClass1
    {
        @Override
        
    public void myMethod1() {}        
    }


    Deprecated

    這個注釋是一個標記注釋。所謂標記注釋,就是在源程序中加入這個標記后,并不影響程序的編譯,但有時編譯器會顯示一些警告信息。

    那么Deprecated注釋是什么意思呢?如果你經常使用eclipseIDE編寫java程序時,可能會經常在屬性或方法提示中看到這個詞。如果某個類成員的提示中出現了個詞,就表示這個并不建議使用這個類成員。因為這個類成員在未來的JDK版本中可能被刪除。之所以在現在還保留,是因為給那些已經使用了這些類成員的程序一個緩沖期。如果現在就去了,那么這些程序就無法在新的編譯器中編譯了。

    說到這,可能你已經猜出來了。Deprecated注釋一定和這些類成員有關。說得對!使用Deprecated標注一個類成員后,這個類成員在顯示上就會有一些變化。在eclipse中非常明顯。讓我們看看圖1有哪些變化。




    加上@Deprecated后的類成員在eclipse中的變化

    從上圖可以看出,有三個地方發生的變化。紅色框里面的是變化的部分。

    1.       方法定義處

    2.       方法引用處

    3.       顯示的成員列表中

    發生這些變化并不會影響編譯,只是提醒一下程序員,這個方法以后是要被刪除的,最好別用。

    Deprecated注釋還有一個作用。就是如果一個類從另外一個類繼承,并且override被繼承類的Deprecated方法,在編譯時將會出現一個警告。如test.java的內容如下:

    class Class1
    {
        @Deprecated
        
    public void myMethod(){}
    }

    class Class2 extends Class1
    {
        
    public void myMethod(){}
    }


    運行javac test.java 出現如下警告:

    注意:test.java 使用或覆蓋了已過時的 API

    注意:要了解詳細信息,請使用 -Xlint:deprecation 重新編譯

    使用-Xlint:deprecation顯示更詳細的警告信息:

    test.java:4: 警告:[deprecation] Class1 中的 myMethod() 已過時

            public void myMethod()

                        ^

    1 警告

    這些警告并不會影響編譯,只是提醒你一下盡量不要用myMethod方法。

    SuppressWarnings

    這個世界的事物總是成對出現。即然有使編譯器產生警告信息的,那么就有抑制編譯器產生警告信息的。

    SuppressWarnings注釋就是為了這樣一個目的而存在的。讓我們先看一看如下的代碼。

    public void myMethod()
    {
        List wordList 
    = new ArrayList();
        wordList.add(
    "foo");
    }

    這是一個類中的方法。編譯它,將會得到如下的警告。

    注意:Testannotation.java 使用了未經檢查或不安全的操作。

    注意:要了解詳細信息,請使用 -Xlint:unchecked 重新編譯。

    這兩行警告信息表示List類必須使用范型才是安全的,才可以進行類型檢查。如果想不顯示這個警告信息有兩種方法。一個是將這個方法進行如下改寫:


    public void myMethod()
    {
        List
    <String> wordList = new ArrayList<String>();
            wordList.add(
    "foo");
    }

    另外一種方法就是使用@SuppressWarnings


    @SuppressWarnings (value={"unchecked"})
    public void myMethod()
    {
        List wordList 
    = new ArrayList();
        wordList.add(
    "foo");
    }

    要注意的是SuppressWarnings和前兩個注釋不一樣。這個注釋有一個屬性。當然,還可以抑制其它警告,如@SuppressWarnings(value={"unchecked", "fallthrough"})

    三、如何自定義注釋

    注釋的強大之處是它不僅可以使java程序變成自描述的,而且允許程序員自定義注釋。注釋的定義和接口差不多,只是在interface前面多了一個“@”。

    public @interface MyAnnotation

    {

    }

    上面的代碼是一個最簡單的注釋。這個注釋沒有屬性。也可以理解為是一個標記注釋。就象Serializable接口一樣是一個標記接口,里面未定義任何方法。

    當然,也可以定義而有屬性的注釋。


    public @interface MyAnnotation

    {
        String value();
    }

    可以按如下格式使用MyAnnotation


    @MyAnnotation(“abc”)

    public void myMethod()

    {
    }

    看了上面的代碼,大家可能有一個疑問。怎么沒有使用value,而直接就寫”abc”了。那么”abc”到底傳給誰了。其實這里有一個約定。如果沒有寫屬性名的值,而這個注釋又有value屬性,就將這個值賦給value屬性,如果沒有,就出現編譯錯誤。

    除了可以省略屬性名,還可以省略屬性值。這就是默認值。


    public @interface MyAnnotation

    {
        
    public String myMethod(){} default “xyz”;
    }

    可以直接使用MyAnnotation


    @MyAnnotation // 使用默認值xyz

    public void myMethod()

    {

    }

    也可以這樣使用


    @MyAnnotation(myMethod=”abc”)

    public void myMethod()

    {

    }

    如果要使用多個屬性的話。可以參考如下代碼。

    public @interface MyAnnotation
    {
        
    public enum MyEnum{A, B, C}
        
    public MyEnum.value1() {}
        
    public String value2() {}
    }

    @MyAnnotation(value1
    =MyAnnotation.MyEnum.A, value2 = “xyz”)
    public void myMethod()
    {
    }

    這一節討論了如何自定義注釋。那么定義注釋有什么用呢?有什么方法對注釋進行限制呢?我們能從程序中得到注釋嗎?這些疑問都可以從下面的內容找到答案。

    四、如何對注釋進行注釋

    這一節的題目讀起來雖然有些繞口,但它所蘊涵的知識卻對設計更強大的java程序有很大幫助。

    在上一節討論了自定義注釋,由此我們可知注釋在J2SE5.0中也和類、接口一樣。是程序中的一個基本的組成部分。既然可以對類、接口進行注釋,那么當然也可以對注釋進行注釋。

    使用普通注釋對注釋進行注釋的方法和對類、接口進行注釋的方法一樣。所不同的是,J2SE5.0為注釋單獨提供了4種注釋。它們是TargetRetention、Documented和Inherited。下面就分別介紹這4種注釋。

    Target

    這個注釋理解起來非常簡單。由于target的中文意思是“目標”,因此,我們可能已經猜到這個注釋和某一些目標相關。那么這些目標是指什么呢?大家可以先看看下面的代碼。


    @Target({ElementType.METHOD})
    @
    interface MyAnnotation {}

    @MyAnnotation         
    // 錯誤的使用
    public class Class1
    {
        @MyAnnotation        
    // 正確的使用
        public void myMethod1() {}
    }

    以上代碼定義了一個注釋MyAnnotation和一個類Class1,并且使用MyAnnotation分別對Class1myMethod1進行注釋。如果編譯這段代碼是無法通過的。也許有些人感到驚訝,沒錯啊!但問題就出在@Target({ElementType.METHOD})上,由于Target使用了一個枚舉類型屬性,它的值是ElementType.METHOD。這就表明MyAnnotation只能為方法注釋。而不能為其它的任何語言元素進行注釋。因此,MyAnnotation自然也不能為Class1進行注釋了。

    說到這,大家可能已經基本明白了。原來target所指的目標就是java的語言元素。如類、接口、方法等。當然,Target還可以對其它的語言元素進行限制,如構造函數、字段、參數等。如只允許對方法和構造函數進行注釋可以寫成:

    @Target({ElementType.METHOD,  ElementType.CONSTRUCTOR})

    @interface MyAnnotation {}

    Retention

    既然可以自定義注釋,當然也可以讀取程序中的注釋(如何讀取注釋將在下一節中討論)。但是注釋只有被保存在class文件中才可以被讀出來。而Retention就是為設置注釋是否保存在class文件中而存在的。下面的代碼是Retention的詳細用法。

    @Retention(RetentionPolicy.SOURCE)

    @interface MyAnnotation1 { }

    @Retention(RetentionPolicy.CLASS)

    @interface MyAnnotation2 {}

    @Retention(RetentionPolicy.RUNTIME)

    @interface MyAnnotation3 {}

    其中第一段代碼的作用是不將注釋保存在class文件中,也就是說象“//”一樣在編譯時被過濾掉了。第二段代碼的作用是只將注釋保存在class文件中,而使用反射讀取注釋時忽略這些注釋。第三段代碼的作用是即將注釋保存在class文件中,也可以通過反射讀取注釋。

    Documented

     

    這個注釋和它的名子一樣和文檔有關。在默認的情況下在使用javadoc自動生成文檔時,注釋將被忽略掉。如果想在文檔中也包含注釋,必須使用Documented為文檔注釋。


    @interface MyAnnotation{ }

    @MyAnnotation
    class Class1
    {    
        
    public void myMethod() { }
    }

    使用javadoc為這段代碼生成文檔時并不將@MyAnnotation包含進去。生成的文檔對Class1的描述如下:

     class Class1extends java.lang.Object

    而如果這樣定義MyAnnotation將會出現另一個結果。

    @Documented

    @interface MyAnnotation {}

    生成的文檔:

    @MyAnnotation // 這行是在加上@Documented后被加上的

    class Class1extends java.lang.Object

    Inherited

    繼承是java主要的特性之一。在類中的protectedpublic成員都將會被子類繼承,但是父類的注釋會不會被子類繼承呢?很遺憾的告訴大家,在默認的情況下,父類的注釋并不會被子類繼承。如果要繼承,就必須加上Inherited注釋。


    @Inherited
    @
    interface MyAnnotation { }

    @MyAnnotation
    public class ParentClass {}

    public class ChildClass extends ParentClass { }

    在以上代碼中ChildClassParentClass一樣都已被MyAnnotation注釋了。

    五、如何使用反射讀取注釋

    前面討論了如何自定義注釋。但是自定義了注釋又有什么用呢?這個問題才是J2SE5.0提供注釋的關鍵。自定義注釋當然是要用的。那么如何用呢?解決這個問題就需要使用java最令人興奮的功能之一:反射(reflect)

    在以前的JDK版本中,我們可以使用反射得到類的方法、方法的參數以及其它的類成員等信息。那么在J2SE5.0中同樣也可以象方法一樣得到注釋的各種信息。

    在使用反射之前必須使用import java.lang.reflect.* 來導入和反射相關的類。

    如果要得到某一個類或接口的注釋信息,可以使用如下代碼:

    Annotation annotation = TestAnnotation.class.getAnnotation(MyAnnotation.class);

    如果要得到全部的注釋信息可使用如下語句:

    Annotation[] annotations = TestAnnotation.class.getAnnotations();

    Annotation[] annotations = TestAnnotation.class.getDeclaredAnnotations();

    getDeclaredAnnotationsgetAnnotations類似,但它們不同的是getDeclaredAnnotations得到的是當前成員所有的注釋,不包括繼承的。而getAnnotations得到的是包括繼承的所有注釋。

    如果要得到其它成員的注釋,可先得到這個成員,然后再得到相應的注釋。如得到myMethod的注釋。

    Method method = TestAnnotation.class.getMethod("myMethod", null);

    Annotation annotation = method.getAnnotation(MyAnnotation.class);

    注:要想使用反射得到注釋信息,這個注釋必須使用

    @Retention(RetentionPolicy.RUNTIME)進行注釋。

    總結

    注釋是J2SE5.0提供的一項非常有趣的功能。它不但有趣,而且還非常有用。如即將出臺的EJB3.0規范就是借助于注釋實現的。這樣將使EJB3.0在實現起來更簡單,更人性化。還有Hibernate3.0除了使用傳統的方法生成hibernate映射外,也可以使用注釋來生成hibernate映射。總之,如果能將注釋靈活應用到程序中,將會使你的程序更加簡潔和強大。






    Android開發完全講義(第2版)(本書版權已輸出到臺灣)

    http://product.dangdang.com/product.aspx?product_id=22741502



    Android高薪之路:Android程序員面試寶典 http://book.360buy.com/10970314.html


    新浪微博:http://t.sina.com.cn/androidguy   昵稱:李寧_Lining

    posted on 2008-05-09 12:46 銀河使者 閱讀(3094) 評論(6)  編輯  收藏 所屬分類: java 原創

    評論

    # re: J2SE5.0中最有趣的新特性:注釋(annotation)[未登錄]  回復  更多評論   

    好像是《精通Hibernate》一書中關于注解的篇章,不知是否是抄襲,感覺抄襲可能性很大
    2008-05-09 13:35 | jones

    # re: J2SE5.0中最有趣的新特性:注釋(annotation)  回復  更多評論   

    很實用,謝謝!
    2008-05-09 14:01 | 宇義

    # re: J2SE5.0中最有趣的新特性:注釋(annotation)  回復  更多評論   

    本文是Java 1.5 Tiger: A Developer's Notebook 的學習總結,沒看過《精通Hibernate》,中文的?誰寫的?如果有些雷同,估計這本英文書是最終的源頭了。

    注釋就這點東西,誰講都是這些內容。上述這本英文書應該是國外最早一批講j2se5.0的書(可是2004年6出的啊),那時國內好象還沒有這種書。
    2008-05-09 14:19 | 銀河使者

    # re: J2SE5.0中最有趣的新特性:注釋(annotation)  回復  更多評論   

    支持原創!收藏了!
    2008-05-09 15:43 | BeanSoft

    # re: J2SE5.0中最有趣的新特性:注釋(annotation)  回復  更多評論   

    寫的極好,很有幫助。。。謝謝
    2008-07-22 13:59 | txf

    # re: J2SE5.0中最有趣的新特性:注釋(annotation)  回復  更多評論   

    明白
    2009-03-03 13:01 | wangs130
    主站蜘蛛池模板: 亚洲精品无码专区久久久| 99久久精品毛片免费播放| 免费在线观看理论片| 黄床大片免费30分钟国产精品| 亚洲AV无码一区二区二三区入口| 国产精品爱啪在线线免费观看| 欧美亚洲精品一区二区| 国产AV无码专区亚洲AV手机麻豆 | 99久久婷婷国产综合亚洲| 国产国产人免费视频成69大陆| 日韩精品无码免费专区午夜 | 久久精品亚洲福利| 黄页免费的网站勿入免费直接进入| 亚洲av无码一区二区三区在线播放| 国产日产亚洲系列| 黄色成人网站免费无码av| 抽搐一进一出gif免费视频| 亚洲成A∨人片天堂网无码| 97视频免费观看2区| 一级做a爰黑人又硬又粗免费看51社区国产精品视 | 亚洲影视一区二区| 免费在线观看一级毛片| 91免费播放人人爽人人快乐| 国产成人高清精品免费观看| 亚洲中文字幕一二三四区| 久久亚洲国产精品| 免费国产一级特黄久久| 免费观看黄色的网站| 国产一级在线免费观看| 久久人午夜亚洲精品无码区| 亚洲福利视频网址| 亚洲高清国产拍精品26U| 亚洲Av无码乱码在线观看性色| 97人妻无码一区二区精品免费| 最近免费中文字幕中文高清 | 国产一级高青免费| 成人国产网站v片免费观看| 亚洲午夜成人精品无码色欲| 亚洲天堂一区二区三区| 亚洲AV日韩AV永久无码久久| 国产成人亚洲精品影院|