自己開發註解
什麼是java註解?
註解是加在java代碼中的一些特殊標記,可以在編譯期間/類加載期間/運行期間/獲取到註解信息,然後執行相應的處理 註解可以加在方法前、類和接口前、方法參數前等,可以使用`@Target`元註解來指定
使用註解的好處,爲什麼要使用註解?
使用註解可以取代xml配置文件。
註解並不影響源代碼的運行
註解的壞處
java註解會需要使用java反射的機制,會大大降低性能。java反射會影響系統性能
註解的維護性有問題需要改源代碼,解耦性稍差
示例:開發一個類似JUnit的@Test註解
-
開發註解,要使用
@Retention
元註解設定好註解的生存時間。在reflect
包下創建一個Annotation
,名爲Test
package reflect; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * 如果一個註解沒有任何的屬性,一般稱之爲標識註解 * 註解默認情況下只會保留到字節碼文件裏面,運行時就會被刪除. * 如果希望在運行時仍然能夠訪問到註解,需要設置註解的生成時間 * @Retention 是一個元註解(即由系統提供,專門用來解釋其他的註解的註解) */ @Retention(RetentionPolicy.RUNTIME) public @interface Test { }
-
將註解添加入源代碼
在
reflect
包下創建一個類,名爲C
package reflect; public class C { public void f1() { System.out.println("C.f1()"); } @Test public void f2() { System.out.println("C.f2()"); } public void hello() { System.out.println("C.hello()"); } }
-
利用反射機制將註解讀取出來,按照業務的需要進行相應的處理
在
reflect
包下創建一個測試類,名爲AnnotationTest
package reflect; import java.lang.reflect.Method; import java.util.Scanner; public class AnnotationTest { public static void main(String[] args) throws Exception { Scanner scanner = new Scanner(System.in); String className = scanner.nextLine(); // 利用反射,獲取類對象 Class cls = Class.forName(className); // 實例化(此種方式實例化要求必須有無參構造器) Object obj = cls.newInstance(); // 獲得該類的所有方法。 // Method用來描述一個方法(包括方法名、參數類型、返回類型,加在方法前的註解等等) Method[] methods = cls.getDeclaredMethods(); for(Method mh : methods) { // 獲得加載方法前的@Test註解(參數是註解對應的class對象) Test test = mh.getAnnotation(Test.class); System.out.println("@Test="+test); if(test != null) { // 只執行帶有@Test註解的方法 mh.invoke(obj); } } } }
執行此
main
方法,在控制檯中輸入reflect.C,打印結果如下(可以看到該註解方法被執行了):reflect.C @Test=null @[email protected]() C.f2() @Test=null
-
給註解添加屬性
註解
Test
類package reflect; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * 如果一個註解沒有任何的屬性,一般稱之爲標識註解 * 註解默認情況下只會保留到字節碼文件裏面,運行時就會被刪除. * 如果希望在運行時仍然能夠訪問到註解,需要設置註解的生成時間 * @Retention 是一個元註解(即由系統提供,專門用來解釋其他的註解的註解) */ @Retention(RetentionPolicy.RUNTIME) public @interface Test { /* * value是註解的屬性(不是方法),類型是String * 類型可以是基本類型,註解類型,數組等等 * 如果註解名爲value,且只有一個屬性,則該註解在使用時,不需要寫屬性名 */ public String value(); }
源代碼類
C
(使用註解的類)package reflect; public class C { public void f1() { System.out.println("C.f1()"); } @Test(value="hello") public void f2() { System.out.println("C.f2()"); } public void hello() { System.out.println("C.hello()"); } }
測試類
package reflect; import java.lang.reflect.Method; import java.util.Scanner; public class AnnotationTest { public static void main(String[] args) throws Exception { Scanner scanner = new Scanner(System.in); String className = scanner.nextLine(); // 利用反射,獲取類對象 Class cls = Class.forName(className); // 實例化(此種方式實例化要求必須有無參構造器) Object obj = cls.newInstance(); // 獲得該類的所有方法。 // Method用來描述一個方法(包括方法名、參數類型、返回類型,加在方法前的註解等等) Method[] methods = cls.getDeclaredMethods(); for(Method mh : methods) { // 獲得加載方法前的@Test註解(參數是註解對應的class對象) Test test = mh.getAnnotation(Test.class); System.out.println("@Test="+test); if(test != null) { // 只執行帶有@Test註解的方法 mh.invoke(obj); // 讀取註解的屬性值 String v = test.value(); System.out.println("註解屬性值v:"+v); } } } }
執行此
main
方法,在控制檯中輸入reflect.C,打印結果如下(可以看到該註解方法被執行了,也打印出了屬性值):reflect.C @Test=null @[email protected](value=hello) C.f2() 註解屬性值v:hello @Test=null