Annotation


在spring、hibernate等流行的開源框架中,基本上來進行配置的方式有兩種,一種是基於配置文件的配置,注入applicationContext.xml或者是hbm.xml,同樣另一種方式則是基於注解的配置,可以說使用注解的配置相當的簡潔明了,所以這里就再來回顧一下什么是Annotation。

一、Annotation基本概念

Annotation是jdk5以后出現的新特性,在jdk中,其內置了許多自己的Annotation,例如@Override,@SuppresWarning,@Deprecated等等,其中一些Annotation是標志性的Annotation,例如@Override就是表示這個類要重寫父類的方法。

我們首先要清楚的知道一點,其實Annotation和Class、Interface這些一樣,都是類級別的,而且我們創建的每一個Annotation都默認的繼承了java.lang.annotation.Annotation這個接口,注意:如果一個接口繼承了這個Annotation接口,那么這個接口並不是一個Annotation

我們接下來自己創建一個簡單的Annotation:

public @interface MyAnnotation
{
    String value();
    String name() default "xiaoluo";
}

這樣就定義了我們自己的一個Annotation了,它的標識符就是  @interface,同樣,Annotation里面可以定義我們的屬性,例如,上面的例子我就定義了兩個String類型的屬性,一個是value屬性,一個是name屬性,注意:在Annotation里定義屬性,屬性后面都要加上括號。同時我們還可以給Annotation的屬性設置默認值,通過 default 這個關鍵字來設置默認值,接下來我們就可以使用我們自己定義的Annotation了:

@MyAnnotation(value="hello", name="world")
public class AnnotationTest
{
    @MyAnnotation("xiaoluo")
    public void hello()
    {
        System.out.println("This is my Annotation!");
    }
}

我們看到,這個時候我們就可以在類上面、方法上面使用我們的Annotation了,注意:在自己定義的Annotation中,如果為其設置了屬性,則我們必須要給其屬性賦值

在上面的例子中,我們看到 @MyAnnotation(value="hello", name="world") 這里就是給其 value屬性和name 屬性賦值,而在下面的那個Annotation中:

@MyAnnotation("xiaoluo"),我們沒有指定其屬性名,那么它是賦值給誰呢?在Annotation中,如果我們定義了一個 value 屬性,那么我們在使用該Annotation,給其賦值時,可以不用寫出屬性的名字,即value

怎么樣,簡單吧,這樣我們就定義並使用了我們的Annotation了。

二、Retention和RetentionPolicy

在初步了解了Annotation之后,我們再來看看Retention和RetentionPolicy這兩個概念,Retention的中文意思是,保留、持有,同樣,Retention也是一個Annotation,通過這個注解,我們可以指定我們自己定義的Annotation的保留范圍,其默認值是有三個,是枚舉類型的值,RetentionPolicy.CLASS(這個是Retention的默認值,表示這個Annotation會被編譯到class文件當中), RetentionPolicy.RESOURCE(這個表示Annotation僅僅在編譯的時候有效,起到提示作用,並不會被編譯到class文件當中去), RetentionPolicy.RUNTIME(這個表示Annotation不僅會被編譯到class文件當中,而且會在JVM運行中也可以得到這個Annotation,這樣我們就可以通過反射來得到Annotaion,並對其進行一些操作了),我們來看看jdk自帶的一些Annotation,其Retention分別是什么:

@Retention(value=SOURCE)
public @interface Override

@Retention(value=SOURCE)
public @interface SuppressWarnings

@Retention(value=RUNTIME)
public @interface Deprecated

我們看到,Deprecated的RetentionPolicy是RUNTIME的,這樣我們可以通過反射在運行時得到其Annotation,接下來我們自己來指定我們剛定義的MyAnnotation為RUNTIME:

@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation
{
    String value();
    String name() default "xiaoluo";
}

這個時候,我們定義的Annotation就會被編譯到class文件當中去,並且在運行時可以得到它,接下來我們來通過一個例子來看看如何使用反射機制得到我們的Annotation以及我們設置的屬性值,java的API指定了訪問得到Annotation的方法,我們的Class,Method,Constructor等等這些都默認實現了 AnnotatedElement 這個接口,這個接口定義了四個常用的方法:

<T extends Annotation> T  getAnnotation(Class<T> annotationClass)    // 根據Annotation.class得到這個Annotation

Annotation[] getAnnotations()    //  得到一個Annotation數組

Annotation[] getDeclaredAnnotations()  //  也是得到一個Annotation數組

boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)    //  判斷是否為被當前的Annotation所標識
@MyAnnotation("hello")
public class AnnotationTest
{
    @MyAnnotation(value="xiaoluo", name="welcome")
    public void hello()
    {
        System.out.println("This is my Annotation!");
    }
    
    public static void main(String[] args) throws Exception
    {
        //    得到AnnotationTest這個類的 class 對象
        Class<AnnotationTest> clazz = AnnotationTest.class;
        
        //    得到AnnotationTest的一個實例對象
        AnnotationTest test = (AnnotationTest)clazz.newInstance();
        
        //    得到方法名為hello的Method對象
        Method method = clazz.getMethod("hello", new Class[]{});
    
        //    判斷hello這個方法是否被MyAnnotation這個注解所標記
        if(method.isAnnotationPresent(MyAnnotation.class))
        {
            //    得到我們的MyAnnotation這個注解
            MyAnnotation myAnnotation = (MyAnnotation)method.getAnnotation(MyAnnotation.class);
            
            System.out.println(myAnnotation.name() + ", " + myAnnotation.value());
            
            method.invoke(test, new Object[]{});
        }
    }
}

我們來看看,因為我們的@MyAnnotation設置了其RetentionPolicy為RUNTIME,所以我們可以在通過反射在運行時得到該Annotation對象,結果輸出為:

welcome, xiaoluo
This is my Annotation!

通過這個例子,我想大家應該知道了RecentPolicy的三個值的含義了吧,我們都可以設置其為RUNTIME,這樣就可以在運行時對其進行判斷來處理我們的業務邏輯了

三、Target和ElementType

最后我們來看看Target和ElementType這兩個東東,Target這個也是一個注解,這個Annotation是用來指定我們的Annotation可以標志的范圍,例如定義在類上,定義在方法上等等,其value就是通過ElementType來指定的,我們來看看ElementType有哪些值:

ANNOTATION_TYPE     // 可以定義在Annotation上

CONSTRUCTOR         // 可以定義在構造函數上

FIELD          // 可以定義屬性上

LOCAL_VARIABLE    // 可以定義在方法的局部變量上

METHOD         // 可以定義在方法上

PACKAGE        // 可以定義在包上
  
PARAMETER       // 可以定義在方法的參數上

TYPE         // 可以定義在類上、接口上

我們也可以在剛才定義的MyAnnotation上設置我們的Target:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation
{
    String value();
    String name() default "xiaoluo";
}

表示MyAnnotation可以定義在類上還有方法上,如果在其他地方定義該注解,則會編譯不通過

好了,Annotation的知識基本就是這些了,主要講解了Annotation的基本概念以及其的一些特性


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM