Java自定義註解開發

阿豪聊乾貨發表於2016-05-18

一、背景

  最近在自己搞一個專案時,遇到可需要開發自定義註解的需求,對於沒有怎麼關注這些java新特性的來說,比較尷尬,索性就拿出一些時間,來進行研究下自定義註解開發的步驟以及使用方式。今天在這裡記下,方便以後學習複習以及分享給有需要的小夥伴們~

二、註解基本概念

  什麼是註解?

    註解就是某種註解型別的一個例項,我們可以用它在某個類上進行標註,這樣編譯器在編譯我們的檔案時,會根據我們自己設定的方法來編譯類。

  註解的分類有哪些?

  

由上圖可知:註解共分為:標記註解、標準元註解、一般註解三類。

注:Deprecated註解,除了多個刪除線,並沒有什麼攔截功能。

  標準元註解詳解

    標準元註解是自定義註解的註解,主要包含4個,都位於java.lang.annotation包中,我們建立自定義註解時會用到4個標準元註解。它們的名稱以及含義如下:

      1. @Documented:用於描述其它型別的annotation應該被作為被標註的程式成員的公共API,因此可以被例如javadoc此類的工具文件化。是一個標記註解,沒有成員。

      2. @Inherited:是一個標記註解闡述了某個被標註的型別是被繼承的。使用了@Inherited修飾的註解型別被用於一個class時該class的子類也有了該註解。

      3. @Retention:定義了該註解的生命週期:某些註解僅出現在原始碼中,而被編譯器丟棄;而另一些卻被編譯在class檔案中;編譯在class檔案中的註解可能會被虛擬機器忽略,而另一些在class被裝載時將被讀取(請注意並不影響class的執行,因為註解與class在使用上是被分離的)。使用這個元註解可以對自定義註解的“生命週期”進行限制。

      生命週期策略列舉

      RetentionPolicy.RUNTIME 註解會在class位元組碼檔案中存在,在執行時可以通過反射獲取到。

      RetentionPolicy.CLASS 預設的保留策略,註解會在class位元組碼檔案中存在,但執行時無法獲得。

      RetentionPolicy.SOURCE 註解僅存在於原始碼中,在class位元組碼檔案中不包含。

      4. @Target:說明了註解所修飾的物件範圍:註解可被用於 packages、types(類、介面、列舉、Annotation型別)、型別成員(方法、構造方法、成員變數、列舉值)、方法引數和本地變數(如迴圈變數、catch引數)。

       修飾範圍列舉

        ElementType.CONSTRUCTOR  作用於構造器
        ElementType.FIELD  作用於域/屬性
        ElementType.LOCAL_VARIABLE  用於描述區域性變數
        ElementType.METHOD  作用於方法
        ElementType.PACKAGE   用於描述包
        ElementType.PARAMETER   用於描述引數
        ElementType.TYPE   用於描述類、介面(包括註解型別) 或enum宣告,最常用

三、開發自定義註解demo

1.開發自定義類註解

 1 package com.hafiz.zhang.annotation;
 2 
 3 import java.lang.annotation.Documented;
 4 import java.lang.annotation.ElementType;
 5 import java.lang.annotation.Retention;
 6 import java.lang.annotation.RetentionPolicy;
 7 import java.lang.annotation.Target;
 8 
 9 /**
10  * @author hafiz.Zhang
11  * @Date 2016年5月18日 下午1:58:11
12  * @Description 自定義類註解
13  */
14 @Documented    //定義可以被文件工具文件化
15 @Retention(RetentionPolicy.RUNTIME)//宣告週期為runtime,執行時可以通過反射拿到
16 @Target(ElementType.TYPE)//註解修飾範圍為類、介面、列舉
17 public @interface ClassAnnotation {
18     public String name() default "defaultService";
19     public String version() default "1.1.0";
20 }

2.自定義方法註解

 1 package com.hafiz.zhang.annotation;
 2 
 3 import java.lang.annotation.Documented;
 4 import java.lang.annotation.ElementType;
 5 import java.lang.annotation.Retention;
 6 import java.lang.annotation.RetentionPolicy;
 7 import java.lang.annotation.Target;
 8 
 9 import com.hafiz.zhang.annotation.en.MethodTypeEnum;
10 
11 /**
12  * @author hafiz.Zhang
13  * @Date 2016年5月18日 下午1:58:26
14  * @Description 自定義方法註解
15  */
16 @Documented
17 @Retention(RetentionPolicy.RUNTIME)
18 @Target(ElementType.METHOD)
19 public @interface MethodAnnotation {
20     public String name() default "defaultName"; 
21     public MethodTypeEnum type() default MethodTypeEnum.TYPE1;
22 }

3.自定義域註解

 1 package com.hafiz.zhang.annotation;
 2 
 3 import java.lang.annotation.Documented;
 4 import java.lang.annotation.ElementType;
 5 import java.lang.annotation.Retention;
 6 import java.lang.annotation.RetentionPolicy;
 7 import java.lang.annotation.Target;
 8 
 9 /**
10  * @author hafiz.Zhang
11  * @Date 2016年5月18日 下午1:58:37
12  * @Description 自定義域註解
13  */
14 @Documented
15 @Target(ElementType.FIELD)
16 @Retention(RetentionPolicy.RUNTIME)
17 public @interface FieldAnnotation {
18     public String name() default "defaultName";
19     public String value() default "defaultValue";
20     
21 }

4.方法型別列舉類

 1 package com.hafiz.zhang.annotation.en;
 2 
 3 /**
 4  * @author hafiz.Zhang
 5  * @Date 2016年5月18日 下午1:59:02
 6  * @Description 方法型別列舉類
 7  */
 8 public enum MethodTypeEnum {
 9     TYPE1,TYPE2
10 }

5.測試註解Bean

 1 package com.hafiz.zhang.annotation.bean;
 2 
 3 import com.hafiz.zhang.annotation.ClassAnnotation;
 4 import com.hafiz.zhang.annotation.FieldAnnotation;
 5 import com.hafiz.zhang.annotation.MethodAnnotation;
 6 import com.hafiz.zhang.annotation.en.MethodTypeEnum;
 7 
 8 /**
 9  * @author hafiz.Zhang
10  * @Date 2016年5月18日 上午11:59:37
11  * @Description 測試使用的bean
12  */
13 @ClassAnnotation(name="personBean", version="1.2.1")
14 public class Person {
15     @FieldAnnotation(name="description", value="This is my personal annotation")
16     private String description;
17 
18     public String getDescription() {
19         return description;
20     }
21 
22     public void setDescription(String description) {
23         this.description = description;
24     }
25     @MethodAnnotation(name="sayHello", type = MethodTypeEnum.TYPE2)
26     public void sayHello() {
27         System.out.println("Hello Annotation!");
28     }
29 }

6.自定義類註解測試類

 1 package com.hafiz.zhang.annotation.test;
 2 
 3 import com.hafiz.zhang.annotation.ClassAnnotation;
 4 import com.hafiz.zhang.annotation.bean.Person;
 5 
 6 /**
 7  * @author hafiz.Zhang
 8  * @Date 2016年5月18日 上午11:56:34
 9  * @Description 測試類註解
10  */
11 public class TestClassAnnotation {
12     
13     private static Person person = new Person();
14     
15     public static void main(String[] args) {
16         Class<?> clazz = person.getClass();
17         //因為註解是作用於類上面的,所以可以通過isAnnotationPresent來判斷是否是一個具有指定註解的類
18         if(clazz.isAnnotationPresent(ClassAnnotation.class)) {
19             System.out.println("This is a class with annotation ClassAnnotation!");
20             //通過getAnnotation可以獲取註解物件
21             ClassAnnotation annotation = clazz.getAnnotation(ClassAnnotation.class);
22             if(null != annotation) {
23                 System.out.println("BeanName = " + annotation.name());
24                 System.out.println("BeanVersion = " + annotation.version());
25             }else{
26                 System.out.println("the annotation that we get is null");
27             }
28         }else{
29             System.out.println("This is not the class that with ClassAnnotation");
30         }
31     }
32 }

執行結果:

7.自定義方法註解測試類

 1 package com.hafiz.zhang.annotation.test;
 2 
 3 import java.lang.reflect.Method;
 4 
 5 import com.hafiz.zhang.annotation.MethodAnnotation;
 6 import com.hafiz.zhang.annotation.bean.Person;
 7 
 8 /**
 9  * @author hafiz.Zhang
10  * @Date 2016年5月18日 下午12:11:11
11  * @Description 測試方法註解
12  */
13 public class TestMethodAnnotation {
14     
15     private static Person person = new Person();
16     
17     public static void main(String[] args) throws Exception {
18         Class<?> clazz = person.getClass();
19         //因為是註解到method上的,所以首先要獲取這個方法
20         Method method = clazz.getDeclaredMethod("sayHello");
21         if(method.isAnnotationPresent(MethodAnnotation.class)) {
22             System.out.println("===This is a method with a annotation:MethodAnnotation===");
23             //通過getAnnotation可以獲取註解物件
24             MethodAnnotation annotation = method.getAnnotation(MethodAnnotation.class);
25             if(null != annotation) {
26                 System.out.println("MethodName = " + annotation.name());
27                 System.out.println("MethodType = " + annotation.type());
28             }else{
29                 System.out.println("the annotation that we get is null");
30             }
31         }else{
32             System.out.println("This is not the class that with MethodAnnotation");
33         }
34     }
35 }

執行結果:

8.自定義域註解測試類

 1 package com.hafiz.zhang.annotation.test;
 2 
 3 import java.lang.reflect.Field;
 4 
 5 import com.hafiz.zhang.annotation.FieldAnnotation;
 6 import com.hafiz.zhang.annotation.bean.Person;
 7 
 8 /**
 9  * @author hafiz.Zhang
10  * @Date 2016年5月18日 下午12:17:49
11  * @Description 測試域註解
12  */
13 public class TestFieldAnnotation {
14     
15     private static Person person = new Person();
16     
17     public static void main(String[] args) throws Exception {
18         Class<?> clazz = person.getClass();
19         //因為是註解到Field上的,所以首先要獲取這個欄位
20         Field field = clazz.getDeclaredField("description");
21         //判斷這個Field上是否有這個註解
22         if(field.isAnnotationPresent(FieldAnnotation.class)) {
23             System.out.println("===This is a field with annotation:FieldAnnotation!===");
24             //如果有這個註解,則獲取註解類
25             FieldAnnotation annotation = field.getAnnotation(FieldAnnotation.class);
26             if(null != annotation){
27                 System.out.println("before set the value is:" + person.getDescription());
28                 //通過反射給私有變數賦值
29                 field.setAccessible(true);
30                 field.set(person, annotation.value());
31                 System.out.println("after set the value is:" + person.getDescription());
32             }else{
33                 System.out.println("the annotation that we get is null");
34             }
35         }else{
36             System.out.println("This is not the class that with FieldAnnotation");
37         }
38     }
39 }

執行結果:

附:demo專案結構圖

以上就是本人對自定義註解開發的理解以及開發測試了,如有錯誤希望大家能夠批評指正!

相關文章