瘋狂Java學習筆記(52)-----------Annotation(注釋)第一篇

來源:互聯網
上載者:User

標籤:

從JDK1.5開始,Java中增加了對中繼資料(MetaData)的支援,也就是Annotation(注釋),這種Annotation與Java程式中的單行注釋和文本注釋是有一定區別,也有一定聯絡的。其實,我們現在說的Annotation是代碼裡的特殊標記,這些標記可以在編譯,類載入,運行時被讀取,並執行相應的處理。通過Annotation,程式開發人員可以在不改變原來邏輯的情況下,在源檔案嵌入一些補充的資訊。程式碼分析工具,開發工具和部署工具可通過這些補充資訊進行驗正或者部署。


  Annotation提供了一條為程式元素設定元素的方法,從某些方面來看,Annotation就象修飾符一樣被使用,可用於修飾包,類,構造器,方法,成員變數,參數,局部變數的聲明,這些資訊被存在Annotation的"name=value"對中。


注意


    Annotation是的一個介面,程式可以通過反射來擷取指定程式元素的Annotation對象,然後通過Annotation對象來取得注釋裡的中繼資料。我們需要注意使用Annotation的地方,有的Annotation指的是java.lang.Annotation介面,有的指的是注釋本身.
  
  Annotation能被用來為程式元素(類,方法,成員變數)設定中繼資料。值得指出的是:Annotation不能影響程式碼的執行,無論增加,刪除Annotation,代碼都始終如一地執行。如果希望讓程式中的Annotation能在運行時起一定的作用,只有通過某種配套的工具對Annotation中的資訊進行訪問和處理,訪問和處理Annotation的工具統稱為APT(Annotation Processing Tool).

一.基本Annotation
  Annotation必須使用工具來處理,工具負責讀取Annotation裡包含的中繼資料,工具還會根據這些中繼資料增加額外的功能。在系統學習新的Annotation文法之前,先看一下Java提供的三個基本Annotation的用法:使用Annotation時要在其前面增加@符號,並把該Annotation當成一個修飾符使用,用於修飾它支援的程式元素.

三個基礎的Annotation如下


@Override
@Deprecated
@SuppressWarings

 

(這三個基本的Annotation都定義在java.lang包下)


下面我們來依次這三個Annotation的用法

(1)限定重寫父類方法 @Override
  @Override就是用來指定方法覆蓋的,它可以強制一個子類必須覆蓋父類的方法。如下程式中使用@Override指定子類Apple的info方法必須重寫父類方法
注意: @Override Annotation只能用於作用於方法,不能用於作用於其它程式元素

執行個體:

<span style="font-size:18px;">class Shape{    void draw(){       System.out.println("形狀");    } } class Circle extends Shape{    //將@Override省略效果相同    @Override    void draw() {       System.out.println("圓形");    } }</span>


 

<span style="font-size:18px;">public class  Fruit{ public void info() {  System.out.println("水果的info方法..."); }}class Apple extends Fruit{ @Override public void info() {  System.out.println("蘋果重寫水果的info方法..."); }}</span>



作用:

編譯上面程式,可能絲毫看不出程式中@Override有任何作用。因為@Override Annotation的作用是告訴編譯器檢查這個方法,並從父類尋找是否包含一個被該方法重寫的方法,否則就編譯出錯。這個Annotation主要是協助我們避免一些低級錯務,例如我們把上面的Apple類中的info方法不小心寫成inf0()方法,這樣的“低級錯務”,可能導致後期排錯時的巨大障礙。

 

(2)標記已淘汰 @Deprecated
@Deprecated 用於表示某個程式元素(類,方法等)已淘汰,當其它程式使用已淘汰的類,方法時,編譯器將會出現警告。如下程式指定Apple類中的info方法已淘汰,其它程式中使用Apple類的info方法時編譯器將會出給出警告。

 

執行個體:

<span style="font-size:18px;">public classTest{    public static void main(String[] args) {       //下面調用shape的draw方法時,編譯器會給出警告       new Shape().draw();    } }   class Shape{    @Deprecated    void draw(){       System.out.println("畫一個形狀");    } }</span>

 

 

<span style="font-size:18px;">class Apple{ //定義info方法已淘汰 @Deprecated public void info() {  System.out.println("Apple的info方法"); }}public class DeprecatedTest{ public static void main(String[] args) {  //下面使用info方法時將會被編譯器警告  new Apple().info(); } }</span>
<span style="font-size:18px;"> </span>

 

(3)@SuppressWarnings 抑制編譯器警告
  @SupressWarnings指示被Annotation標識的程式元素(以及在程式元素中的所有子項目)取消顯示指定的編譯器警告。 @SuppressWarnings會一直作用於該程式元素的所有子項目,例如使用@SuppressWarning標識一個類來取消某個編譯器警告,同時又標識該類裡某個方法取消另一個編譯器警告,那麼將在此方法中同時取消這兩個編譯器警告。

  通常情況下,如果程式中使用沒有泛型限制的集合將會引起編譯器警告,為了避免這種編譯器警告,可以使用@SuppressWarnings Annotation,下面程式取消了沒有使用泛型的編譯器警告。

 

<span style="font-size:18px;color:#000000;">@SuppressWarnings(value="unchecked")public class SuppressWarningsTest{ public static void main(String[] args) {  List<String> myList = new ArrayList();   } }</span>


 

<span style="font-size:18px;">//關閉整個類裡的編譯器警告 @SuppressWarnings("unchecked") public class Test{    public static void main(String[]args) {       List<String> tempList = new ArrayList();    } }</span>


 

說明:
  a.程式中使用@SuppressWarnings來關閉SuppressWarningTest類裡的所有編譯器警告,編譯上面程式時將不會看到任何編譯器警告。

 

       b.當我們使用@SuppressWarnings Annotation來關閉編譯器警告時,一定要在插號裡使用name=value對來為該Annotation的成員變數設定值.

 

 

二.自訂Annotation
  前面已經介紹了如何使用java.lang包下的三個標準Annotation。下面介紹如何定義 Annotation,並利用Annotation完成一些實際的功能。

(1)定義Annotation
  定義新的Annotation類型時使用@interface關健字(在原有的interface關健字前增加@符號),它用於定義新的Annotation類型。定義一個新的Annotation類型與定義一個介面非常像。

如下代碼定義一個簡單的Annotation

<span style="font-size:18px;">//使用@Test修飾類定義@Testpublic class MyClass{...}</span>



  定義該Annotation之後,就可以在程式任何地方使用該Annotation ,使用Annotation時的文法非常類似於public ,final這樣的修飾符,通常可以用於修飾程式中的類,方法,變數,介面等定義。
  通常我們會把Annotation放在所有修飾符之前,而且由於使用Annotation時可能還需要為其它成員變數指定值,因而Annotation的長度可能較長,所以通常把Annotaion另放一行.

<span style="font-size:18px;">//使用@Test修飾類定義@Testpublic class MyClass{...}</span>


 預設情況下,Annotation可用於修飾任何元素,包括類,介面,方法等。如下程式使用@TestAnnotation來修飾方法

 

public class MyClass{   //使用@TestAnnotation修飾方法   @Test   public void info()   { ...   }}


Annotation不僅可以是這種簡單的Annotation,Annotation還可以帶用員變數,Annotation的成員變數在Annotation定義中以無參數來聲明。其方法和返回值定義了該成員的名字和類型。


如下代碼可以定義一個有成員變數的Annotation
public @interface MyTag
{
    //定義兩個成員變數Annotation
    //Annotation中的成員變數以方法的形式來定義
    String name();
    int age();
}

 

 

 仔細觀察:上面定義Annotation的代碼與定義介面的文法非常像,只是上面MyTag使用@interface關健字來定義,而介面使用interface來定義

 一旦在Annotation裡定義了成員變數之後,使用該Annotation時應該為該Annotation的成員變數指定值,

 

如下代碼所示


public class Test
{
    //使用帶成員變數的Annotation時,需要為成員變數付值
    MyTag(name=‘heyitang‘,age=30)
    public void info()
    {
 ...
    }
}

  我們還可以在定義Annotation的成員變數時為其指定初始值,指定成員變數的初始值可使用default關健字。如下代碼定義了MyTag Annotaion,該Annotation裡包含了兩個成員:name和age,這兩個成元變數使用default指定了預設值
public @interface MyTag
{
   //定義了兩個成員變數的Annotaion
   //以default為兩個成員變數指定初始值
   String name() default "yeeku";
   int age() default 32;
}
 
  如果為Annotation的成員變數指定了預設值,使用該Annotation則可以不為這些成員變數指定值,而是直接使用預設值,如下代碼所示
public class Test
{
    //使用帶成員變數的Annotation
    //因為它的成員變數有預設值,所以可以無須為成員變數指定值
    @MyTag
    public void info()
    {
        ...
    }
}

    當然我們介紹的Annotation是否可以包含成員指定值,如果MyTag為的成員變數指定了值,則預設值不會起作用


    總結
       根據我們介紹的Annotation是否可以包含成員變數,我們可以把Annotation分為如下兩類
       1.標記Annotation:一個沒有成員變數的Annotation類型被稱為標記。這種Annotation僅合使用自身的存在與否來為我們提供資訊。如前面介紹的@Override,@Test等Annotation
       2.中繼資料Annotation:那些包含成員變數的Annotation,因為它們可接受更多中繼資料,所以也被稱為中繼資料Annotation


 

(2)提取Annotation
  前面已經提到:JAVA使用Annotation介面來代表元素前面的注釋,該接品是所有Annotation類型的父介面。除此之外,JAVA在java.lang.reflect包下新增了AnnotationElement介面,該介面代表程式中可以接受注釋的程式元素,該介面主要有如下幾個實作類別.

    Class:類定義
    Constructor:構造器定義
    Field:類的成員變數定義
    Method:類的方法定義
    Package:類的包定義

    AnnotationElement介面是所有程式元素(如Class,Method,Constructor)的父介面,所以程式通過反射擷取某個類的了AnnotationElement對象(如Class,Method,和Constructor)之後,程式就可以調用該對象的如下三個方法來訪問Annotation資訊


    getAnnotation(Class<T> annotationClass):返回該程式元素上存在的,指定類型的注釋
    Annotation[] getAnnotations:返回該程式元素上存在的所有注釋
    boolean isAnnotationPreset(Class<? extends Annotation> annotationClass):判斷該程式元素上是否包含指定類型的注釋,存在則返回true,否則返回false

 

(3)使用Annotation的例子
  下面介紹兩個使用Annotation的例子,第一個Annotation Testable沒有任何成員變數,僅是一個標記Annotation,它的作用是標記哪些方法是可測試的.
Testable.java源檔案。

 

Testable.java源檔案import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME)   @Target(ElementType.METHOD)//定義Testable Annotation將被javadoc工具提取@Documentedpublic @interface Testable{}


 

上面程式定義了一個標記Testable Annotation,定義該Annotation時使用了@Retention和@Target兩個系統元注釋,其中@Retention注釋指明Testabel注釋可以保留多久,而@Target注釋指定Testable能修飾的目標(只能是方法)。

 

 

  如下MyTest測試案例裡定義了8個方法,這8個方法沒有太大的區別,其中四個方法使用@testable注釋來標記這些方法是可測試的

 

public class MyTest{ //使用@Testable標記注釋指定該方法是可測試的 @Testable public static void m1() { } public static void m2() { }   //使用@Testable標記注釋指定該方法是可測試的 @Testable public static void m3() {         throw new RuntimeException("Boom");  } public static void m4() { }       //使用@Testable標記注釋指定該方法是可測試的 @Testable public static void m5() { }     public static void m6() { } //使用@Testable標記注釋指定該方法是可測試的 @Testable public static void m7() {             throw new RuntimeException("Crash");   }        public static void m8() { }}


 


正如前面提到的,僅僅使用注釋來標記程式元素對程式是不會有任何影響的,這也是注釋的一條重要原則,為了讓程式中這些注釋起作用,我們必須為這些注釋提供一個注釋處理工具。

 

下面的注釋處理工具分析目標類,如果目標類中方法使用了@Testable注釋修飾,則通過反射來運行該測試方法

 

import java.lang.reflect.*;public class TestProcessor{ public static void process(String clazz)  throws ClassNotFoundException {  int passed = 0;  int failed = 0;  //遍曆obj對象的所有方法  for (Method m : Class.forName(clazz).getMethods())  {   //如果包含@Testable標記注釋   if (m.isAnnotationPresent(Testable.class))   {    try    {     //調用m方法     m.invoke(null);     //passed加1     passed++;    }    catch (Exception ex)    {     System.out.printf("方法" + m + "運行失敗,異常:" + ex.getCause() + "\n");     failed++;    }   }  }  //統計測試結果  System.out.printf("共運行了:" + (passed + failed)+ "個方法,其中:\n" +   "失敗了:" + failed + "個,\n" +    "成功了:" + passed + "個!\n"); }}


 

參考博文:http://blog.sina.com.cn/s/blog_4c925dca0100hseu.html

                 http://blog.csdn.net/zhai56565/article/details/40503743

 

 

 

瘋狂Java學習筆記(52)-----------Annotation(注釋)第一篇

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.