一、背景
最近在自己搞一個專案時,遇到可需要開發自定義註解的需求,對於沒有怎麼關注這些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專案結構圖
以上就是本人對自定義註解開發的理解以及開發測試了,如有錯誤希望大家能夠批評指正!