在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的基本概念以及其的一些特性