1. 程式人生 > >Java之註解篇

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、註解的本質:註解是一種型別
JDK5.0中的型別:1、類(class)2、介面(interface)3、列舉(enum)4、註解(Annotation) 因此,註解與其他3種類型一樣,都可以定義、使用,以及包含有自己的屬性、方法 4、註解的分類: (1)標記註釋:註解的內部沒有屬性,稱作標記註解 使用方法:@註解名 使用例子:@MarkAnnotation (2)單值註解:註解的內部只有一個屬性,稱作單值註解 使用方法:@註解名(屬性名=屬性值) 使用例子:@SingleAnnotation(value="abc")  //也可以寫成@SingleAnnotation("abc") *(屬性名=屬性值)可以簡化為(屬性值),但是需要滿足以下兩個條件: 1、該註解必須為單值註解 2、該註解的屬性名必須為value (3)多值註解:註解的內部有多個屬性,稱作多值註解 使用方法:@註解名(屬性名1=屬性值1, 屬性名2=屬性值2……) 使用例子:@MultipliedAnnotation(value1 = "abc", value2 = 30……) /*********以下內容為擴充套件知識*********/ 5、自定義註解: 用途:用於開發人員在開發程式的過程中測試指令 ***********分界線:測試人員的測試步驟********** 測試步驟: 1、寫出一個測試類 2、在主方法中建立一個需要測試的物件 3、由於需要被測試的物件某些方法不能被呼叫,而某些方法又不需要被呼叫(即:需要被測試的物件僅僅有某些方法需要被呼叫),因此程式的開發人員需要通過註釋來通知測試人員哪些方法需要被呼叫 4、由於測試的時候需要使用臨界測試點來測試程式(即:使用最容易使程式出錯的引數來測試程式),因此程式的開發人員需要通過註釋來通知測試人員什麼樣的引數為程式的臨界測試點 *測試的目的:儘可能發現程式中的錯誤,而不是證明程式的正確性 *****************分界線結束**************** 因此,由於需要被測試的方法以及臨界測試點都是需要由開發人員通過註釋來通知測試人員的,因此開發人員可以通過使用Annotation來直接通知虛擬機器來對程式進行測試,而不再需要測試人員 定義註解的語法: public @interface TestCase {  //注意在這裡使用的是@interface而不是@class   String value() ;   //定義該註解的屬性(注意註釋中的屬性和方法是不區分的,每一個元素既是屬性,也是方法,因此上句也可以被理解成方法的定義) String value() default "TestValue";   //定義該註解的屬性時,定義預設的屬性值 } 6、元註解:系統提供的註解,用於註解自定義註解 元註解理解: 註解可以用於註解類(annotate Classes) 可以用於註解介面(annotate Interfaces) 可以用於註解列舉型別(annotate Enums) 因此註解同樣也可以用於註解註解(annotate Annotations) (1)@Target註解: @Target註解是一個單值註釋,唯一的屬性名為value value型別:ElementType的陣列 *ElementType ElementType是一個列舉型別,它在其中定義了 ANNOTATION_TYPE    註釋
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());       }     }   } }