熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java核心技術 >> 正文

基礎學習教程:Java Annotation入門

2013-11-23 18:41:07  來源: Java核心技術 

  摘要

  本文針對java初學者或者annotation初次使用者全面地說明了annotation的使用方法定義方式分類初學者可以通過以上的說明制作簡單的annotation程序但是對於一些高級的annotation應用(例如使用自定義annotation生成javabean映射xml文件)還需要進一步的研究和探討涉及到深入annotation的內容作者將在後文《Java Annotation高級應用》中談到

  同時annotation運行存在兩種方式運行時編譯時上文中討論的都是在運行時的annotation應用但在編譯時的annotation應用還沒有涉及

  為什麼使用Annotation

  在JAVA應用中我們常遇到一些需要使用模版代碼例如為了編寫一個JAXRPC web service我們必須提供一對接口和實現作為模版代碼如果使用annotation對遠程訪問的方法代碼進行修飾的話這個模版就能夠使用工具自動生成

  另外一些API需要使用與程序代碼同時維護的附屬文件例如JavaBeans需要一個BeanInfo Class與一個Bean同時使用/維護而EJB則同樣需要一個部署描述符此時在程序中使用annotation來維護這些附屬文件的信息將十分便利而且減少了錯誤

  Annotation工作方式

  在版之前的Java平台已經具有了一些ad hoc annotation機制比如使用transient修飾符來標識一個成員變量在序列化子系統中應被忽略而@deprecated這個javadoc tag也是一個ad hoc annotation用來說明一個方法已過時從Java版發布以來平台提供了一個正式的annotation功能允許開發者定義使用自己的annoatation類型此功能由一個定義annotation類型的語法和一個描述annotation聲明的語法讀取annotaion的API一個使用annotation修飾的class文件一個annotation處理工具(apt)組成

  annotation並不直接影響代碼語義但是它能夠工作的方式被看作類似程序的工具或者類庫它會反過來對正在運行的程序語義有所影響annotation可以從源文件class文件或者以在運行時反射的多種方式被讀取

  當然annotation在某種程度上使javadoc tag更加完整一般情況下如果這個標記對java文檔產生影響或者用於生成java文檔的話它應該作為一個javadoc tag否則將作為一個annotation

  Annotation使用方法

  類型聲明方式

  通常應用程序並不是必須定義annotation類型但是定義annotation類型並非難事Annotation類型聲明於一般的接口聲明極為類似區別只在於它在interface關鍵字前面使用@符號

  annotation類型的每個方法聲明定義了一個annotation類型成員但方法聲明不必有參數或者異常聲明方法返回值的類型被限制在以下的范圍primitivesStringClassenumsannotation和前面類型的數組方法可以有默認值

  下面是一個簡單的annotation類型聲明

  清單

   


  /**
     * Describes the RequestForEnhancement(RFE) that led
     * to the presence of the annotated API element
     */
    public @interface RequestForEnhancement {
        int    id();
        String synopsis();
        String engineer() default [unassigned];
        String date();    default [unimplemented];
    }

  代碼中只定義了一個annotation類型RequestForEnhancement

  修飾方法的annotation聲明方式

  annotation是一種修飾符能夠如其它修飾符(如publicstaticfinal)一般使用習慣用法是annotaions用在其它的修飾符前面annotations由@+annotation類型+帶有括號的成員值列表組成這些成員的值必須是編譯時常量(即在運行時不變)

  A下面是一個使用了RequestForEnhancement annotation的方法聲明

  清單

  


  @RequestForEnhancement(
        id       =
        synopsis = Enable timetravel
        engineer = Mr Peabody
        date     = //
    )
    public static void travelThroughTime(Date destination) { }

  B當聲明一個沒有成員的annotation類型聲明時可使用以下方式


   清單

  


  /**
     * Indicates that the specification of the annotated API element
     * is preliminary and subject to change
     */
    public @interface Preliminary { }

 作為上面沒有成員的annotation類型聲明的簡寫方式

  清單

  

 


  @Preliminary public class TimeTravel { }

  C如果在annotations中只有唯一一個成員則該成員應命名為value

  

  清單

  

 


  /**
     * Associates a copyright notice with the annotated API element
     */
    public @interface Copyright {
        String value();
    }

  更為方便的是對於具有唯一成員且成員名為value的annotation(如上文)在其使用時可以忽略掉成員名和賦值號(=)

  清單


  @Copyright( Yoyodyne Propulsion Systems)
    public class OscillationOverthruster { }

  一個使用實例

  結合上面所講的我們在這裡建立一個簡單的基於annotation測試框架首先我們需要一個annotation類型來表示某個方法是一個應該被測試工具運行的測試方法

  清單


  import javalangannotation*;

    /**
     * Indicates that the annotated method is a test method
     * This annotation should be used only on parameterless static methods
     */
    @Retention(RetentionPolicyRUNTIME)
    @Target(ElementTypeMETHOD)
    public @interface Test { }

  值得注意的是annotaion類型聲明是可以標注自己的這樣的annotation被稱為metaannotations

  在上面的代碼中@Retention(RetentionPolicyRUNTIME)這個metaannotation表示了此類型的annotation將被虛擬機保留使其能夠在運行時通過反射被讀取而@Target(ElementTypeMETHOD)表示此類型的annotation只能用於修飾方法聲明

  下面是一個簡單的程序其中部分方法被上面的annotation所標注

  清單


  public class Foo {
        @Test public static void m() { }
        public static void m() { }
        @Test public static void m() {
            throw new RuntimeException(Boom);
        }
        public static void m() { }
        @Test public static void m() { }
        public static void m() { }
        @Test public static void m() {
            throw new RuntimeException(Crash);
        }
        public static void m() { }
    }

Here is the testing tool:

    import javalangreflect*;

    public class RunTests {
       public static void main(String[] args) throws Exception {
          int passed = failed = ;
          for (Method m : ClassforName(args[])getMethods()) {
             if (misAnnotationPresent(Testclass)) {
                try {
                   minvoke(null);
                   passed++;
                } catch (Throwable ex) {
                   Systemoutprintf(Test %s failed: %s %n m exgetCause());
                   failed++;
                }
             }
          }
          Systemoutprintf(Passed: %d Failed %d%n passed failed);
       }
    }

  這個程序從命令行參數中取出類名並且遍歷此類的所有方法嘗試調用其中被上面的測試annotation類型標注過的方法在此過程中為了找出哪些方法被annotation類型標注過需要使用反射的方式執行此查詢如果在調用方法時拋出異常此方法被認為已經失敗並打印一個失敗報告最後打印運行通過/失敗的方法數量

  下面文字表示了如何運行這個基於annotation的測試工具

  清單

  

 


  $ java RunTests Foo
    Test public static void Foom() failed: javalangRuntimeException: Boom
    Test public static void Foom() failed: javalangRuntimeException: Crash
    Passed: Failed

  Annotation分類

  根據annotation的使用方法和用途主要分為以下幾類

  內建Annotation——Java版在java語法中經常用到的內建Annotation

  @Deprecated用於修飾已經過時的方法

  @Override用於修飾此方法覆蓋了父類的方法(而非重載)

  @SuppressWarnings用於通知java編譯器禁止特定的編譯警告

  下面代碼展示了內建Annotation類型的用法

  清單

  

 


  package combjinfotechpracticeannotation;

/**
 * 演示如何使用java內建的annotation
 * 參考資料
 * ml
 * /docs/guide/language/l
 *
 * @author cleverpig
 *
 */
import javautilList;

public class UsingBuiltInAnnotation {
        //食物類
        class Food{}
        //干草類
        class Hay extends Food{}
        //動物類
        class Animal{
                Food getFood(){
                        return null;
                }
                //使用Annotation聲明Deprecated方法
                @Deprecated
                void deprecatedMethod(){
                }
        }
        //馬類繼承動物類
        class Horse extends Animal{
                //使用Annotation聲明覆蓋方法
                @Override
                Hay getFood(){
                        return new Hay();
                }
                //使用Annotation聲明禁止警告
                @SuppressWarnings({deprecationunchecked})
                void callDeprecatedMethod(List horseGroup){
                        Animal an=new Animal();
                        andeprecatedMethod();
                        horseGroupadd(an);
                }
        }
}

  開發者自定義Annotation由開發者自定義Annotation類型

  下面是一個使用annotation進行方法測試的sample

  AnnotationDefineForTestFunction類型定義如下

  清單

   


  package combjinfotechpracticeannotation;

import javalangannotation*;
/**
 * 定義annotation
 * @author cleverpig
 *
 */
//加載在VM中在運行時進行映射
@Retention(RetentionPolicyRUNTIME)
//限定此annotation只能標示方法
@Target(ElementTypeMETHOD)
public @interface AnnotationDefineForTestFunction{}

  測試annotation的代碼如下

  清單

  

 


  package combjinfotechpracticeannotation;

import javalangreflect*;

/**
 * 一個實例程序應用前面定義的AnnotationAnnotationDefineForTestFunction
 * @author cleverpig
 *
 */
public class UsingAnnotation {
        @AnnotationDefineForTestFunction public static void method(){}
        
        public static void method(){}
        
        @AnnotationDefineForTestFunction public static void method(){
                throw new RuntimeException(method);
        }
        
        public static void method(){
                throw new RuntimeException(method);
        }
        
        public static void main(String[] argv) throws Exception{
                int passed = failed = ;
                //被檢測的類名
                String className=combjinfotechpracticeannotationUsingAnnotation;
                //逐個檢查此類的方法當其方法使用annotation聲明時調用此方法
            for (Method m : ClassforName(className)getMethods()) {
               if (misAnnotationPresent(AnnotationDefineForTestFunctionclass)) {
                  try {
                     minvoke(null);
                     passed++;
                  } catch (Throwable ex) {
                     Systemoutprintf(測試 %s 失敗: %s %n m exgetCause());
                     failed++;
                  }
               }
            }
            Systemoutprintf(測試結果通過: %d 失敗 %d%n passed failed);
        }
}

  使用第三方開發的Annotation類型

  這也是開發人員所常常用到的一種方式比如我們在使用Hibernate時就可以利用Annotation生成數據表映射配置文件而不必使用Xdoclet

  總結

 前面的文字說明了annotation的使用方法定義方式分類初學者可以通過以上的說明制作簡單的annotation程序但是對於一些高級的annotation應用(例如使用自定義annotation生成javabean映射xml文件)還需要進一步的研究和探討

 同時annotation運行存在兩種方式運行時編譯時上文中討論的都是在運行時的annotation應用但在編譯時的annotation應用還沒有涉及因為編譯時的annotation要使用annotation processing tool


From:http://tw.wingwit.com/Article/program/Java/hx/201311/25569.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.