Java之註解篇
瞭解註解
我們有必要對JDK 5.0新增的註解(Annotation)技術進行簡單的學習,因為Spring 支援@AspectJ,而@AspectJ本身就是基於JDK 5.0的註解技術。所以學習JDK 5.0的註解知識有助於我們更好地理解和掌握Spring的AOP技術。
對於Java開發人員來說,在編寫程式碼時,除了源程式以外,我們還會使用 Javadoc標籤對類、方法或成員變數進行註釋,以便使用Javadoc工具生成和原始碼配套的Javadoc文件。這些@param、@return 等Javadoc標籤就是註解標籤,它們為第三方工具提供了描述程式程式碼的註釋資訊。使用過Xdoclet的朋友,對此將更有感觸,像Struts、 Hibernate都提供了Xdoclet標籤,使用它們可以快速地生成對應程式程式碼的配置檔案。
JDK5.0註解可以看成是Javadoc標籤和Xdoclet標籤的延伸和發展。在JDK5.0中,我們可以自定義這些標籤,並通過Java語言的反射機制中獲取類中標註的註解,完成特定的功能。
註解是程式碼的附屬資訊,它遵循一個基本原則:註解不能直接干擾程式程式碼的執行,無論增加或刪除註解,程式碼都能夠正常執行。Java語言直譯器會忽略這些註解,而由第三方工具負責對註解進行處理。第三方工具可以利用程式碼中的註解間接控制程式程式碼的執行,它們通過Java反射機制讀取註解的資訊,並根據這些資訊更改目標程式的邏輯,而這正是Spring AOP對@AspectJ提供支援所採取的方法。
註解的語法比較簡單,除了@符號的使用以外,它基本上與java的固有語法一致,java內建了三種註解,定義在java.lang包中。
@Override:只能用在方法之上的,用來告訴別人這一個方法是改寫父類的。
@Deprecated:建議別人不要使用舊的API的時候用的,編譯的時候會用產生警告資訊,可以設定在程式裡的所有的元素上。
@SuppressWarnings:表示關閉一些不當的編譯器警告資訊。
1、與註釋的區別: 註釋:描述程式碼的文字 即:這種註釋只是需要給人看,而機器本身並不會執行 註解:描述程式碼的程式碼 即:註解不僅僅是給人看,而且機器本身也會將其作為程式碼執行 2、註解的作用: 規定某個方法的作用,用於檢查某個方法的定義是否起到了註解中規定的作用,例如: @Override //規定下一個方法的作用為覆蓋父類裡的方法 public String toStirng { //在此處拼錯了toString return "Success!"; } //則編譯出錯 3、註解的本質:註解是一種型別CONSTRUCTOR 構造方法
FIELD 成員變數
LOCAL_VARIABLE 區域性變數
METHOD 方法
PACKAGE 包
PARAMETER 引數
TYPE 型別(?)
定義方法:@Target (value = {METHOD, FIELD, ...}) @Target的作用:表示該自定義註釋寫出來後能夠註釋什麼元素型別(能夠註解的元素型別,就是在定義@Target時value陣列中的值(ElementType型別)) (2)@Retention註解: @Retention註解是一個單值註釋,唯一的屬性名為value value型別:RetentionPolicy型別 *RetentionPolicy RetentionPolicy是一個列舉型別,它在其中定義了 SOURCE 表示該自定義註釋僅僅是提供給編譯器對程式進行檢查的依據,在編譯的過程中,該自定義註釋就會被清除掉(即:不會被儲存到.class檔案中) CLASS 表示該自定義註釋會在.class檔案中保留,但是當該.class檔案被載入到虛擬機器(產生類物件)的時候,該註釋就會被清除掉(即:不會被載入到虛擬機器中) RUNTIME 表示該自定義註釋不會被忽略,僅有此種類型的註釋會被保留到執行時,並可以在類物件中察看
定義方法:@Retention (value = SOURCE/CLASS/RUNTIME) @Retention的作用:表示該自定義註釋會被保留到什麼時候(能夠保留到的時候,就是在定義@Rentention的時候value中的值(RetentionPolicy型別)) 7、自動測試機的寫法: 自動測試機的原理: 使用Annotation來Annotate元素的實質是:每一個ElementType內部的元素都有兩個方法,分別為 (注:為方便理解,以下使用的TestCase為某個特定的自定義註釋) (1)isAnnotationPresent(TestCase.class) //判斷該元素是否被TestCase所註釋 (2)getAnnotation(TestCase.class) //獲得TestCase的類物件 因此,自動測試機的工作過程是: (1)首先通過反射,獲得被測類o中的每一個方法 (2)對每一個方法通過使用isAnnotationPresent(TestCase.class)判斷其是否被TestCase所註釋(注意是.class!) (3)如果某方法method被TestCase所註釋,則通過method的getAnnotation(TestCase.class)獲得TestCase的類物件tc (4)通過tc的value()方法,獲得該類物件的屬性value (注:此處使用的value()方法,正是在TestCase中定義的value屬性,再次理解在註釋中定義的value既是屬性,也是方法) (5)呼叫method方法的invoke(o,value),用value對method進行測試 8、註解使用例項: 要求: (1)定義一個單值註解TestCase,使其可以註解方法,並且可以被保留到程式執行時 註解的屬性型別為String,要求可以使用簡寫方式為屬性賦值 (2)定義一個類MyClass,要求有三個方法Method1、2、3 方法的引數、返回值型別均為String型別,返回值為傳入的引數 使用(1)中的註解來註釋Method1、3,並對屬性引數賦值 (3)定義一個測試類TestMyClass,要求使用反射來測試MyClass中所有的被TestCase註解的方法 並將註解的屬性值作為引數,呼叫相應方法來返回測試結果 例子: ---------------------------1--------------------------- import java.lang.annotation.*; @Target ({ElementType.METHOD}) @Retention (RetentionPolicy.RUNTIME) public @interface TestCase { String value(); } ---------------------------2--------------------------- public class MyClass { @TestCase("This is Method 1") public String Method1 (String s) { return s; } public String Method2 (String s) { return s; } @TestCase("This is Method 3") public String Method3 (String s) { return s; } } ---------------------------3--------------------------- import java.lang.reflect.*; public class TestMyClass { public static void main(String [] args) { Class c = Class.forName("MyClass"); Method [] ms = c.getDeclaredMethods(); for (Method m : ms) { if(m.isAnnotationPresent(TestCase.class) { TestCase tc = m.getAnnotation(TestCase.class); Object o = c.newInstance(); String s = tc.value(); m.invoke(o, s); 或者以上三句可以直接寫成: m.invoke(c.newInstace, tc.value()); } } } }