Java Annotation 注釋文法

來源:互聯網
上載者:User
 JAVA從J2SE5開始提供名為annotation(注釋,標註)的功能。Java的annotation,可以附加在package, class, method, field等上面,相當於給它們添加了額外的輔助資訊。附加在package, class, method, field等上的Annotation,如果沒有外部解析工具等對其加以解析和處理的情況,本身不會對Java的原始碼或class等產生任何影響,也不 會對它們的執行產生任何影響。

但藉助外部工具,比如javac,EJB容器等,可以對附加在package, class, method, field的annotation進行解析,可以根據annotation而做出相應的處理,比如運行時改變對象/方法的行為。

Java標準Annotation

@Deprecated 相當於Javadoc的@deprecated,被@Deprecated標註的對象class, method等被註明為不推薦使用。主要用於javac等編譯工具。

@Override 註明對象method重載了父類的方法。javac等編譯工具編譯時間會根據此Annotation判斷重載方法是否正確。

@SuppressWarnings 告訴javac等編譯器忽略所指定的特定的警告資訊。

@Target 被定義的annotation可以附加在那些對象上。

@Retention annotation的作用期間。

Java標準Annotation的使用

@Deprecated:

@Deprecated

public class TestBean {

    …

}

@SuppressWarnings:

@SuppressWarnings("serial ")

public class TestBean implements java.io.Serializable {

    …

}

@SuppressWarnings(value = {"serial ", "unchecked "})

public String doSth() {

    …

}

@Override:

@Override

public String doSth() {

    …

}

Annotation的定義

定義方法:

@interface Annotation名 {定義體}

定義例1:

public @interface MyAnnotation {}

該例定義了一個無任何屬性/方法的Annotation。

定義例2:

public @interface MyAnnotation {

    public String value();

}

該例定義了只有一個方法為value()的Annotation。一般來說,只有一個方法的Annotation,方法名一定定義為value。

定義例3:

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.METHOD)

public @interface MyAnnotation {

    public String value();

    public String [] multiValues();

    int number() default 0;

   

}

該例定義了一個具有多方法的Annotation。並設定其中一個方法number的預設值為0。multiValues 方法定義為數群組類型。Annotation定義可以用MetaAnnotation(元注釋)修飾。MetaAnnotation有以下2個:

@Retention

@Target

我們將在以下對@Retention與@Target加以說明。

@Retention

@Retention 可以設定為RetentionPolicy類型的值。

例:

@Retention(RetentionPolicy.RUNTIME)

RetentionPolicy的值 說明

RetentionPolicy.CLASS annotation資訊將被編譯器編譯時間儲存在class檔案中,但執行時不會在VM裝載。也就是說不能在執行時動態取得annotation資訊。未設定@Retention時這將是預設設定值。

RetentionPolicy.RUNTIME annotation資訊將被編譯器編譯時間儲存在class檔案中,執行時也會被VM裝載。

RetentionPolicy.SOURCE annotation資訊將被編譯器編譯時間捨棄掉。

@Target

@Target表明Annotation可以附加在哪種JAVA元素之上,可以設定為java.lang.annotation.ElementType數群組類型的值。

使用例1:

@Target(ElementType.METHOD)

使用例2:

@Target(value={ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.LOCAL_VARIABLE, ElementType.METHOD})

ElementType是一個枚舉類型,它具有以下定義:

ElementType值 說明

ElementType.ANNOTATION_TYPE 應用於其他註解的元註解

ElementType.CONSTRUCTOR 建構函式

ElementType.FIELD 欄位

ElementType.LOCAL_VARIABLE 方法中的本地變數

ElementType.METHOD 方法

ElementType.PACKAGE 包

ElementType.PARAMETER 方法的參數

ElementType.TYPE 類,介面或者枚舉聲明

自訂 Java Annotation

Annotation是一種特殊的interface。所以可以在annotation裡定義方法,屬性;也可以讓某個類從annotation繼承(implements)。

下面從簡單地範例開始,讓我們一步步加深對annotation的瞭解。

無任何方法/屬性Annotation範例:

MyAnnotation0.java

package com.test.annotation;

public @interface MyAnnotation0 {

   

}

MyAnnotation0為一個無任何方法和屬性的annotation。

使用MyAnnotation0:

TestMyAnnotation0.java

@MyAnnotation0

public class TestMyAnnotation0 {

    @MyAnnotation0

    public void testMethod() {

    }

}

具有一個value方法Annotation範例:

MyAnnotation1.java

public @interface MyAnnotation1 {

   

    /**

     * value method

     * @return value

     */

    public String value();

}

MyAnnotation1具有一個名為value的方法。

MyAnnotation1使用:

TestMyAnnotation1.java

@MyAnnotation1("hello ")

public class TestMyAnnotation1 {

    @MyAnnotation1(value="world ")

    public void testMethod() {

    }

}

可以通過@Annotation名(方法名1=值1, 方法名2=值2,
…)的形式給annotation賦值。只有一個方法的時候,可以直接省略為:@Annotation名(值1)
的賦值形式。當方法返回一個數組時,可以用 方法名={值1, 值2, …}給其賦值。

具有一個value方法和一個屬性Annotation範例:

如果必要,還可以在annotation裡為其定義屬性。如下:

MyAnnotation2.java

@interface MyAnnotation2 {

    public String value();

    public String myProperty = "hello world ";

}

其中,myProperty只能申明為public或無public修飾(無public修飾時也預設為public)為static, final屬性(即使不寫也預設為static, final)。

使用例:

TestMyAnnotation2

class TestMyAnnotation2 {

    public static void main(String[] args) {

        System.out.println(MyAnnotation2.myProperty);

    }

    @MyAnnotation2("")

    public void testMethod1() {

    }

}

上例會列印出:

hello world

複雜型annotation的定義與使用

本節介紹較為複雜的annotation定義與使用。

先看代碼:

MyAnnotation3.java

public @interface MyAnnotation3 {

    public String value();

    public String[] multiValues();

    int number() default 0;

}

MyAnnotation3具有一個返回String的value方法,返回String[]的multiValues 方法;還有一個返回int 的number方法。其中number方法具有預設值0。

使用例:

TestMyAnnotation3.java

class TestMyAnnotation3 {

    @MyAnnotation3(value = "call testMethod1 ", multiValues={"1 ", "2 "}, number = 1)

    public void testMethod1() {

    }

    @MyAnnotation3(value = "call testMethod2 ", multiValues={"1 ", "2 "})

    public void testMethod2() {

    }

}

number具有預設值,所以標註時可以不為其賦值。其餘方法則必須通過上面介紹的方法賦值。multiValues返回一個String[]數組,所以可以通過multiValues={"1", "2"}為其賦值。

這樣說來,annotation到底能起什麼作用呢?

1,    編譯工具或其他工具可以根據被附加在代碼裡的annotation資訊自動組建組態檔案或文檔等外部檔案。

比如,sun公司就提供了apt(Annotation Processing Tool)
工具,apt工具是一個可以處理annotation的命令列工具,apt提供了在編譯期針對原始碼層級的解析,並可以在解析時產生新的原始碼和其他文
件,同時還可以對產生的原始碼進行編譯。

2,    其他程式可以在運行時動態解析將要被執行的程式裡的annotation資訊,並根據被附加的annotation資訊來執行不同的操作。

比如,EJB3規範就比較廣泛地使用了annotation特性。比如只要在POJO為class註明@Stateless注釋,EJB容器便會
根據此 annotation把該POJO註冊為無狀態的Session
Bean。EJB3使用了annotation大大地簡化了EJB的開發和配置過程。我們會在其他文章裡專門介紹EJB
Annotation的原理與使用方法,這裡不做詳述。

本文通過一個簡單地例子來說明怎麼在運行期動態解析annotation。Apt工具的使用我們會在近期其他文章裡對其加以介紹。

比如,我們定義了MyAnnotation3注釋:

MyAnnotation3.java

package com.test.annotation;

import java.lang.annotation.Annotation;

import java.lang.annotation.Inherited;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)

public @interface MyAnnotation3 {

    public String value();

    public String[] multiValues();

    int number() default 0;

}

上面定義了一個名為MyAnnotation3的注釋。

我們再定義一個GetMyAnnotation類,該類使用了MyAnnotation3注釋:

GetMyAnnotation.java:

package com.test.annotation.test;

import java.lang.annotation.Annotation;

import java.lang.reflect.Field;

import java.lang.reflect.Method;

import javax.ejb.EJB;

import javax.naming.InitialContext;

import javax.naming.NamingException;

import com.test.annotation.MyAnnotation3;

// 為GetMyAnnotation類附加MyAnnotation3 注釋

@MyAnnotation3(value = "Class GetMyAnnotation ", multiValues = {"1 ","2 "})

public class GetMyAnnotation {

    // 為testField1屬性附加MyAnnotation3 注釋

    @MyAnnotation3(value = "call testField1 ", multiValues={"1 "}, number = 1)

    private String testField1;

    // 為testMethod1方法附加MyAnnotation3 注釋

    @MyAnnotation3(value = "call testMethod1 ", multiValues={"1 ", "2 "}, number = 1)

    public void testMethod1() {

    }

    @Deprecated

    @MyAnnotation3(value = "call testMethod2 ", multiValues={"3 ", "4 ", "5 "})

    public void testMethod2() {

    }

}

上面的例子GetMyAnnotation非常簡單,裡面沒有任何功能,但是分別為類(class),屬性(field),方法(method)申明(附加)了MyAnnotation3 注釋。

下面我們用程式TestMyAnnotation3對GetMyAnnotation裡MyAnnotation3注釋進行解析。

運行時解析annotation

TestMyAnnotation3.java

public class TestMyAnnotation3 {

    public static void main(String[] args) {

        System.out.println("--Class Annotations-- ");

        if (GetMyAnnotation.class.isAnnotationPresent(MyAnnotation3.class )) {

            System.out.println("[GetMyAnnotation].annotation: ");

            MyAnnotation3 classAnnotation = GetMyAnnotation.class.getAnnotation(MyAnnotation3.class );

            printMyAnnotation3(classAnnotation);

        }

       

       

        System.out.println("--Fields Annotations-- ");

        Field [] fields = GetMyAnnotation.class.getDeclaredFields();

        for (Field field : fields) {

            if (field.isAnnotationPresent(MyAnnotation3.class )) {

                System.out.println("[GetMyAnnotation. " + field.getName() + "].annotation: ");

                MyAnnotation3 fieldAnnotation = field.getAnnotation(MyAnnotation3.class );

                printMyAnnotation3(fieldAnnotation);

            }

        }

       

        System.out.println("--Methods Annotations-- ");

        Method[] methods = GetMyAnnotation.class.getDeclaredMethods();

        for (Method method : methods) {

            System.out.println("[GetMyAnnotation. " + method.getName() + "].annotation: ");

            if (method.isAnnotationPresent(MyAnnotation3.class )) {

                MyAnnotation3 methodAnnotation = method.getAnnotation(MyAnnotation3.class );

                printMyAnnotation3(methodAnnotation); 

            }

        }

    }

   

    private static void printMyAnnotation3(MyAnnotation3 annotation3) {

        if (annotation3 == null ) {

            return;

        }

       

        System.out.println("{value= " + annotation3.value());

       

        String multiValues = "";

        for (String value: annotation3.multiValues()) {

            multiValues += ", " + value;

        }

       

        System.out.println("multiValues= " + multiValues);

       

        System.out.println("number= " + annotation3.number() + "} ");

    }

}

輸出:

--Class Annotations--

[GetMyAnnotation].annotation:

{value=Class GetMyAnnotation

multiValues=,1,2

number=0}

--Fields Annotations--

[GetMyAnnotation.testField1].annotation:

{value=call testField1

multiValues=,1

number=1}

--Methods Annotations--

[GetMyAnnotation.testMethod1].annotation:

{value=call testMethod1

multiValues=,1,2

number=1}

[GetMyAnnotation.testMethod2].annotation:

{value=call testMethod2

multiValues=,3,4,5

number=0}

JDK1.5以後的版本提供的跟annotation有關的介面:

interface java.lang.reflect.AnnotatedElement {

    boolean isAnnotationPresent(Class<? extends Annotation> annotationClass);

    <T extends Annotation> T getAnnotation(Class<T> annotationClass);

    Annotation[] getAnnotations();

    Annotation[] getDeclaredAnnotations();

}

該介面主要用來取得附加在類(class),構造方法(constructor),屬性(field),方法(method),包(package)上的annotation資訊。

JDK1.5與此有關的幾個類都實現了AnnotatedElement介面:

java.lang.reflect.AccessibleObject,

java.lang.reflect.Class,

java.lang.reflect.Constructor,

java.lang.reflect.Field,

java.lang.reflect.Method,

java.lang.reflect.Package

所以可以利用反射(reflection)功能在程式裡動態解析附加的annotation資訊。

總結:

本文通過舉例簡單地說明了怎麼動態解析annotation,大家可以舉一反三,利用Java的annotation特性,完成更複雜功能等。   

 

Trackback:http://yelinsen.iteye.com/blog/1051886

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.