標籤:深入理解java java註解 annotation 註解處理器 annotatedelement
從 JDK 5.0 開始, Java 增加了對中繼資料(MetaData) 的支援, 也就是 Annotation(註解)
Annotation 其實就是代碼裡的特殊標記, 這些標記可以在編譯, 類載入, 運行時被讀取, 並執行相應的處理. 通過使用 Annotation, 程式員可以在不改變原有邏輯的情況下, 在源檔案中嵌入一些補充資訊.
Annotation 可以像修飾符一樣被使用, 可用於修飾包,類, 構造器, 方法, 成員變數, 參數, 局部變數的聲明, 這些資訊被儲存在 Annotation 的 “name=value” 對中.
Annotation 能被用來為程式元素(類, 方法, 成員變數等) 設定中繼資料
三個基本的 Annotation:
@Override: 限定重寫父類方法, 該注釋只能用於方法
@Deprecated: 用於表示某個程式元素(類, 方法等)已淘汰
@SuppressWarnings: 抑制編譯器警告
JDK5.0提供了專門在註解上的註解類型,分別是:
1.Retention
2.Target
3.Documented
4.Inherited
@Retention: 只能用於修飾一個 Annotation 定義, 用於指定該 Annotation 可以保留多長時間, @Rentention 包含一個 RetentionPolicy 類型的成員變數, 使用 @Rentention 時必須為該 value 成員變數指定值:
RetentionPolicy.SOURCE: 編譯器直接丟棄這種策略的注釋
RetentionPolicy.CLASS: 編譯器將把注釋記錄在 class 檔案中. 當運行 Java 程式時, JVM 不會保留注 解。 這是預設值
RetentionPolicy.RUNTIME:編譯器將把注釋記錄在 class 檔案中. 當運行 Java 程式時, JVM 會保留注釋. 程式可以通過反射擷取該注釋
@Target: 用於修飾 Annotation 定義, 用於指定被修飾的 Annotation 能用於修飾哪些程式元素. @Target 也包含一個名為 value 的成員變數.
@Documented: 用於指定被該元 Annotation 修飾的 Annotation 類將被 javadoc 工具提取成文檔.
定義為Documented的註解必須設定Retention值為RUNTIME。
@Inherited: 被它修飾的 Annotation 將具有繼承性.如果某個類使用了被 @Inherited 修飾的 Annotation, 則其子類將自動具有該註解
實際應用中,使用較少
註解處理器類庫(java.lang.reflect.AnnotatedElement):
Java使用Annotation介面來代表程式元素前面的註解,該介面是所有Annotation類型的父介面。除此之外,Java在java.lang.reflect 包下新增了AnnotatedElement介面,該介面代表程式中可以接受註解的程式元素,該介面主要有如下幾個實作類別:
Class:類定義
Constructor:構造器定義
Field:累的成員變數定義
Method:類的方法定義
Package:類的包定義
java.lang.reflect 包下主要包含一些實現反射功能的工具類,實際上,java.lang.reflect 包所有提供的反射API擴充了讀取運行時Annotation資訊的能力。當一個Annotation類型被定義為運行時的Annotation後,該註解才能是運行時可見,當class檔案被裝載時被儲存在class檔案中的Annotation才會被虛擬機器讀取。
AnnotatedElement 介面是所有程式元素(Class、Method和Constructor)的父介面,所以程式通過反射擷取了某個類的AnnotatedElement對象之後,程式就可以調用該對象的如下四個個方法來訪問Annotation資訊:
方法1:<T extends Annotation> T getAnnotation(Class<T> annotationClass): 返回改程式元素上存在的、指定類型的註解,如果該類型註解不存在,則返回null。
方法2:Annotation[] getAnnotations():返回該程式元素上存在的所有註解。
方法3:boolean is AnnotationPresent(Class<?extends Annotation> annotationClass):判斷該程式元素上是否包含指定類型的註解,存在則返回true,否則返回false.
方法4:Annotation[] getDeclaredAnnotations():返回直接存在於此元素上的所有注釋。與此介面中的其他方法不同,該方法將忽略繼承的注釋。(如果沒有注釋直接存在於此元素上,則返回長度為零的一個數組。)該方法的調用者可以隨意修改返回的數組;這不會對其他調用者返回的數組產生任何影響。
一個簡單的註解處理器:
/***********註解聲明***************//** * 水果名稱註解 * @author yang * */@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface FruitName { String value() default "";}/** * 水果顏色註解 * @author yang * */@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface FruitColor { /** * 顏色枚舉 * @author peida * */ public enum Color{ BULE,RED,GREEN}; /** * 顏色屬性 * @return */ Color fruitColor() default Color.GREEN;}/** * 水果供應者註解 * @author yang * */@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface FruitProvider { /** * 供應商編號 * @return */ public int id() default -1; /** * 供應商名稱 * @return */ public String name() default ""; /** * 供應商地址 * @return */ public String address() default "";}/***********註解使用***************/public class Apple { @FruitName("Apple") private String appleName; @FruitColor(fruitColor=Color.RED) private String appleColor; @FruitProvider(id=1,name="陝西紅富士集團",address="陝西省西安市延安路89號紅富士大廈") private String appleProvider; public void setAppleColor(String appleColor) { this.appleColor = appleColor; } public String getAppleColor() { return appleColor; } public void setAppleName(String appleName) { this.appleName = appleName; } public String getAppleName() { return appleName; } public void setAppleProvider(String appleProvider) { this.appleProvider = appleProvider; } public String getAppleProvider() { return appleProvider; } public void displayName(){ System.out.println("水果的名字是:蘋果"); }}/***********註解處理器***************/public class FruitInfoUtil { public static void getFruitInfo(Class<?> clazz){ String strFruitName=" 水果名稱:"; String strFruitColor=" 水果顏色:"; String strFruitProvicer="供應商資訊:"; Field[] fields = clazz.getDeclaredFields(); for(Field field :fields){ if(field.isAnnotationPresent(FruitName.class)){ FruitName fruitName = (FruitName) field.getAnnotation(FruitName.class); strFruitName=strFruitName+fruitName.value(); System.out.println(strFruitName); } else if(field.isAnnotationPresent(FruitColor.class)){ FruitColor fruitColor= (FruitColor) field.getAnnotation(FruitColor.class); strFruitColor=strFruitColor+fruitColor.fruitColor().toString(); System.out.println(strFruitColor); } else if(field.isAnnotationPresent(FruitProvider.class)){ FruitProvider fruitProvider= (FruitProvider) field.getAnnotation(FruitProvider.class); strFruitProvicer=" 供應商編號:"+fruitProvider.id()+" 供應商名稱:"+fruitProvider.name()+" 供應商地址:"+fruitProvider.address(); System.out.println(strFruitProvicer); } } }}/***********輸出結果***************/public class FruitRun { /** * @param args */ public static void main(String[] args) { FruitInfoUtil.getFruitInfo(Apple.class); }}==================================== 水果名稱:Apple 水果顏色:RED 供應商編號:1 供應商名稱:陝西紅富士集團 供應商地址:陝西省西安市延安路89號紅富士大廈
Java註解的基礎知識點(見下面導圖)基本都過了一遍,下一篇我們通過設計一個基於註解的簡單的ORM架構,來綜合應用和進一步加深對註解的各個知識點的理解和運用。
650) this.width=650;" src="https://s5.51cto.com/wyfs02/M00/98/76/wKioL1k8zU6h-WbfAAdDqAiRht8629.jpg" title="25200814-475cf2f3a8d24e0bb3b4c442a4b44734.jpg" alt="wKioL1k8zU6h-WbfAAdDqAiRht8629.jpg" />
本文出自 “ciyo技術分享” 部落格,請務必保留此出處http://ciyorecord.blog.51cto.com/6010867/1934218
JAVA註解Annotation