Annotation之一:Java Annotation基本功能介绍
一、元數據的作用
如果要對于元數據的作用進行分類,目前還沒有明確的定義,不過我們可以根據它所起的作用,大致可分為三類:
二、jdk基本內置注釋
??? @Override注釋能實現編譯時檢查,你可以為你的方法添加該注釋,以聲明該方法是用于覆蓋父類中的方法。如果該方法不是覆蓋父類的方法,將會在編譯時報錯。例如我們為某類重寫toString()方法卻寫成了tostring(),并且我們為該方法添加了@Override注釋;
???? @Deprecated的作用是對不應該在使用的方法添加注釋,當編程人員使用這些方法時,將會在編譯時顯示提示信息,它與javadoc里的@deprecated標記有相同的功能,準確的說,它還不如javadoc @deprecated,因為它不支持參數,
注意:要了解詳細信息,請使用 -Xlint:deprecation 重新編譯。(見《注解中的-Xlint:unchecked和 -Xlint:deprecation》)
??? @SuppressWarnings與前兩個注釋有所不同,你需要添加一個參數才能正確使用,這些參數值都是已經定義好了的,我們選擇性的使用就好了,參數如下:
- deprecation?? 使用了過時的類或方法時的警告
- unchecked? 執行了未檢查的轉換時的警告,例如當使用集合時沒有用泛型 (Generics) 來指定集合保存的類型
- fallthrough?? 當 Switch 程序塊直接通往下一種情況而沒有 Break 時的警告
- path?? 在類路徑、源文件路徑等中有不存在的路徑時的警告
- serial 當在可序列化的類上缺少 serialVersionUID 定義時的警告
- finally??? 任何 finally 子句不能正常完成時的警告
- all 關于以上所有情況的警告
注意:要了解詳細信息,請使用 -Xlint:unchecked 重新編譯。(見《Annotation之四:注解中的-Xlint:unchecked和 -Xlint:deprecation》)
?
在定義自己的注解之前,我們就必須要了解Java為我們提供的元注解和相關定義注解的語法。
三、Java5.0中新增的4種元注解:
元注解的作用就是負責注解其他注解。Java5.0定義了4個標準的meta-annotation類型,它們被用來提供對其它 annotation類型作說明。
- 注解方法不能有參數。
- 注解方法的返回類型局限于原始類型,字符串,枚舉,注解,或以上類型構成的數組。
- 注解方法可以包含默認值。
- 注解可以包含與其綁定的元注解,元注解為注解提供信息,
Java5.0以后jdk定義了四種元注解有:
1、@Documented –注解文檔提取,注解是否將包含在JavaDoc中。
2、@Retention –注解保留策略,什么時候使用該注解。
3、@Target? –注解修飾目標,注解用于什么地方。
4、@Inherited – 注解繼承聲明,是否允許子類繼承該注解。
3.1、@Documented
@Documented用于描述其它類型的annotation應該被作為被標注的程序成員的公共API,因此可以被例如javadoc此類的工具文檔化。Documented是一個標記注解,沒有成員。
示例說明:看下面的示例加強理解下:
package com.dxz.nettydemo.duan; import java.lang.annotation.Target; import java.lang.annotation.Documented; import java.lang.annotation.ElementType;@Documented @Target(ElementType.TYPE) public @interface Table {/*** 數據表名稱注解,默認值為類名稱* @return*/public String tableName() default "className"; }用javadoc生成doc文檔
javadoc -encoding UTF-8 Table.java打開html文件可以看到java源碼中的注釋信息,如下:
?
3.2、@Retention
@Retention定義了該Annotation被保留的時間長短:某些Annotation僅出現在源代碼中,而被編譯器丟棄;而另一些卻被編譯在class文件中;編譯在class文件中的Annotation可能會被虛擬機忽略,而另一些在class被裝載時將被讀取(請注意并不影響class的執行,因為Annotation與class在使用上是被分離的)。使用這個meta-Annotation可以對 Annotation的“生命周期”限制。
作用:表示需要在什么級別保存該注釋信息,用于描述注解的生命周期(即:被描述的注解在什么范圍內有效)
取值(RetentionPoicy)有:
1.RetentionPolicy.SOURCE:在源文件中有效(--?注解只存在于源代碼中,字節碼Class文件中將不存在該注解。)
2.RetentionPolicy.CLASS:在class文件中有效(?--?標明注解只會被編譯器編譯后保留在Class字節碼文件中,而運行時無法獲取。)
3.RetentionPolicy.RUNTIME:在運行時有效(--?標明注解會保留在class字節碼文件中,且運行時能通過反射機制獲取。)
Retention meta-annotation類型有唯一的value作為成員,它的取值來自java.lang.annotation.RetentionPolicy的枚舉類型值。
?
示例說明:Column注解的的RetentionPolicy的屬性值是RUTIME,這樣注解處理器可以通過反射,獲取到該注解的屬性值,從而去做一些運行時的邏輯處理。
package com.dxz.nettydemo.duan;import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Column {public String name() default "fieldName";public String setFuncName() default "setField";public String getFuncName() default "getField"; public boolean defaultDBValue() default false; }?
3.3、@Target?
@Target說明了Annotation所修飾的對象范圍:Annotation可被用于 packages、types(類、接口、枚舉、Annotation類型)、類型成員(方法、構造方法、成員變量、枚舉值)、方法參數和本地變量(如循環變量、catch參數)。在Annotation類型的聲明中使用了target可更加明晰其修飾的目標。
作用:用于描述注解的使用范圍(即:被描述的注解可以用在什么地方)
如果不明確指出,該注解可以放在任何地方。以下是一些可用的參數。需要說明的是:屬性的注解是兼容的,如果你想給7個屬性都添加注解,僅僅排除一個屬性,那么你需要在定義target包含所有的屬性。
取值(ElementType)有:
?示例說明,上面示例中的代碼表明:注解Table 可以用于注解類、接口(包括注解類型) 或enum聲明
@Target(ElementType.TYPE) public @interface Table {...
3.4、@Inherited?
@Inherited 元注解是一個標記注解,@Inherited闡述了某個被標注的類型是被繼承的。如果一個使用了@Inherited修飾的annotation類型被用于一個class,則這個annotation將被用于該class的子類。
注意:@Inherited annotation類型是被標注過的class的子類所繼承。類并不從它所實現的接口繼承annotation,方法并不從它所重載的方法繼承annotation。
當@Inherited annotation類型標注的annotation的Retention是RetentionPolicy.RUNTIME,則反射API增強了這種繼承性。如果我們使用java.lang.reflect去查詢一個@Inherited annotation類型的annotation時,反射代碼檢查將展開工作:檢查class和其父類,直到發現指定的annotation類型被發現,或者到達類繼承結構的頂層。
?詳細見《Annotation之二:@Inherited注解繼承情況》
四、自定義注解
使用@interface自定義注解時,自動繼承了java.lang.annotation.Annotation接口,由編譯程序自動完成其他細節。在定義注解時,不能繼承其他的注解或接口。@interface用來聲明一個注解,其中的每一個方法實際上是聲明了一個配置參數。方法的名稱就是參數的名稱,返回值類型就是參數的類型(返回值類型只能是基本類型、Class、String、enum)。可以通過default來聲明參數的默認值。
1、定義注解格式:
public @interface 注解名 {定義體}注解參數的可支持數據類型:
1.所有基本數據類型(int,float,boolean,byte,double,char,long,short)
2.String類型
3.Class類型
4.enum類型
5.Annotation類型
6.以上所有類型的數組
Annotation類型里面的參數該怎么設定:?
第一,只能用public或默認(default)這兩個訪問權修飾.例如,String value();這里把方法設為defaul默認類型;
第二,參數成員只能用基本類型byte,short,char,int,long,float,double,boolean八種基本數據類型和 String,Enum,Class,annotations等數據類型,以及這一些類型的數組.例如,String value();這里的參數成員就為String;
第三,如果只有一個參數成員,最好把參數名稱設為"value",后加小括號.例:下面的例子FruitName注解就只有一個參數成員。
2、@interface說明:
3、根據Annotation是否包含成員變量,可以把Annotation分為兩類:
?
簡單的自定義注解和使用注解實例:
package com.dxz.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/*** 水果名稱注解*/ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface FruitName {String value() default ""; } package com.dxz.annotation;import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/*** 水果顏色注解*/ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface FruitColor {/*** 顏色枚舉*/public enum Color {BULE, RED, GREEN};/*** 顏色屬性* @return*/Color fruitColor() default Color.GREEN; } package com.dxz.annotation;import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface FruitProvider {int id() default 0;String user() default "duan";String address() default "shenzhen futian";} package com.dxz.annotation;import com.dxz.annotation.FruitColor.Color;public class Apple {@FruitName("Apple")private String appleName;@FruitColor(fruitColor = Color.RED)private String appleColor;@FruitProvider(id=1,user="Tom",address="China")private FruitProvider provider; }package com.dxz.annotation;import java.lang.reflect.Field;public class Test {public static void getFruitInfo(String clas) {try {Class<?> cls = Class.forName(clas);Field[] fields = cls.getDeclaredFields();for (Field field : fields) {if (field.isAnnotationPresent(FruitName.class) == true) {FruitName name = field.getAnnotation(FruitName.class);System.out.println("Fruit Name:" + name.value());}if (field.isAnnotationPresent(FruitColor.class)) {FruitColor color = field.getAnnotation(FruitColor.class);System.out.println("Fruit Color:" + color.fruitColor());}if (field.isAnnotationPresent(FruitProvider.class)) {FruitProvider Provider = field.getAnnotation(FruitProvider.class);System.out.println("Fruit FruitProvider: ProviderID:"+ Provider.id() + " Provider:" + Provider.user()+ " ProviderAddress:" + Provider.address());}}} catch (ClassNotFoundException e) {e.printStackTrace();}}public static void main(String[] args) {getFruitInfo("com.dxz.annotation.Apple");}}結果:
Fruit Name:Apple Fruit Color:RED Fruit FruitProvider: ProviderID:1 Provider:Tom ProviderAddress:China?
注解元素的默認值:
注解元素必須有確定的值,要么在定義注解的默認值中指定,要么在使用注解時指定,非基本類型的注解元素的值不可為null。因此, 使用空字符串或0作為默認值是一種常用的做法。這個約束使得處理器很難表現一個元素的存在或缺失的狀態,因為每個注解的聲明中,所有元素都存在,并且都具有相應的值,為了繞開這個約束,我們只能定義一些特殊的值,例如空字符串或者負數,一次表示某個元素不存在,在定義注解時,這已經成為一個習慣用法。
?
五、讀取注釋信息(Java注解解析)
當我們想讀取某個注釋信息時,我們是在運行時通過反射來實現的,如果你對元注釋還有點印象,那你應該記得我們需要將保持性策略設置為RUNTIME,也就 是說只有注釋標記了@Retention(RetentionPolicy.RUNTIME)的,我們才能通過反射來獲得相關信息。
詳細見《Annotation之三:自定義注解示例,利用反射進行解析》
六、為注解增加高級屬性
6.1、數組類型的屬性
- 增加數組類型的屬性:int[] arrayAttr() default {1,2,4};
- 應用數組類型的屬性:@MyAnnotation(arrayAttr={2,4,5})
- 如果數組屬性只有一個值,這時候屬性值部分可以省略大括號,如:@MyAnnotation(arrayAttr=2),這就表示數組屬性只有一個值,值為2
6.2.、枚舉類型的屬性
- 增加枚舉類型的屬性:EumTrafficLamp lamp() default EumTrafficLamp.RED;
- 應用枚舉類型的屬性:@MyAnnotation(lamp=EumTrafficLamp.GREEN)
6.3、注解類型的屬性
package com.dxz.annotation;/*** MetaAnnotation注解類為元注解*/ public @interface MetaAnnotation {String value();// 元注解MetaAnnotation設置有一個唯一的屬性value }為注解添加一個注解類型的屬性,并指定注解屬性的缺省值:MetaAnnotation annotationAttr() default @MetaAnnotation("xdp");
6.4、示例
package com.dxz.annotation;public enum EumTrafficLamp {RED, // 紅YELLOW, // 黃GREEN// 綠 } package com.dxz.annotation;import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME) //Retention注解決定MyAnnotation注解的生命周期 @Target({ ElementType.METHOD, ElementType.TYPE }) public @interface MyAnnotation {String color() default "blue";// 為屬性指定缺省值/*** 為注解添加value屬性,這個value屬性很特殊,如果一個注解中只有一個value屬性要設置,* 那么在設置注解的屬性值時,可以省略屬性名和等號不寫, 直接寫屬性值,如@SuppressWarnings("deprecation"),* 這里的MyAnnotation注解設置了兩個String類型的屬性,color和value,* 因為color屬性指定有缺省值,value屬性又是屬于特殊的屬性,因此使用MyAnnotation注解時* 可以這樣使用MyAnnotation注解:"@MyAnnotation(color="red",value="xdp")"* 也可以這樣使用:"@MyAnnotation("* test")",這樣寫就表示MyAnnotation注解只有一個value屬性要設置,color屬性采用缺省值* 當一個注解只有一個value屬性要設置時,是可以省略"value="的*/String value();// 定義一個名稱為value的屬性// 添加一個int類型數組的屬性int[] arrayAttr() default { 1, 2, 4 };// 添加一個枚舉類型的屬性,并指定枚舉屬性的缺省值,缺省值只能從枚舉類EumTrafficLamp中定義的枚舉對象中取出任意一個作為缺省值EumTrafficLamp lamp() default EumTrafficLamp.RED;// 為注解添加一個注解類型的屬性,并指定注解屬性的缺省值MetaAnnotation annotationAttr() default @MetaAnnotation("xdp");} package com.dxz.annotation;/*** 這里是將新創建好的注解類MyAnnotation標記到AnnotaionTest類上, 并應用了注解類MyAnnotation中定義各種不同類型的的屬性*/ @MyAnnotation(color = "red", value = "test", arrayAttr = { 3, 5, 6 }, lamp = EumTrafficLamp.GREEN, annotationAttr = @MetaAnnotation("gacl")) public class MyAnnotationTest {@MyAnnotation("將MyAnnotation注解標注到main方法上")public static void main(String[] args) {/*** 這里是檢查Annotation類是否有注解,這里需要使用反射才能完成對Annotation類的檢查*/if (MyAnnotationTest.class.isAnnotationPresent(MyAnnotation.class)) {/*** 用反射方式獲得注解對應的實例對象后,在通過該對象調用屬性對應的方法* MyAnnotation是一個類,這個類的實例對象annotation是通過反射得到的,這個實例對象是如何創建的呢?* 一旦在某個類上使用了@MyAnnotation,那么這個MyAnnotation類的實例對象annotation就會被創建出來了*/MyAnnotation annotation = (MyAnnotation) MyAnnotationTest.class.getAnnotation(MyAnnotation.class);System.out.println("annotation.color():"+annotation.color());// 輸出color屬性的默認值:redSystem.out.println("annotation.value():"+annotation.value());// 輸出value屬性的默認值:testSystem.out.println("annotation.arrayAttr().length:"+annotation.arrayAttr().length);// 這里輸出的數組屬性的長度的結果為:3,數組屬性有三個元素,因此數組的長度為3System.out.println("annotation.lamp():"+annotation.lamp());// 這里輸出的枚舉屬性值為:GREENSystem.out.println("annotation.annotationAttr().value():"+annotation.annotationAttr().value());// 這里輸出的注解屬性值:gacl MetaAnnotation ma = annotation.annotationAttr();// annotation是MyAnnotation類的一個實例對象System.out.println("ma.value():"+ma.value());// 輸出的結果為:gacl }} }結果:
annotation.color():red annotation.value():test annotation.arrayAttr().length:3 annotation.lamp():GREEN annotation.annotationAttr().value():gacl ma.value():gacl?
七、Java并發編程中,用到了一些專門為并發編程準備的 Annotation
主要包括三類:
1、類 Annotation(注解)
就像名字一樣,這些注解是針對類的。主有要以下三個:
- @Immutable
- @ThreadSafe
- @NotThreadSafe
@Immutable 表示,類是不可變的,包含了 @ThreadSafe 的意思。
@ThreadSafe 是表示這個類是線程安全的。具體是否真安全,那要看實現者怎么實現的了,反正打上這個標簽只是表示一下。不線程安全的類打上這個注解也沒事兒。
@NotThreadSafe 表示這個類不是線程安全的。如果是線程安全的非要打上這個注解,那也不會報錯。
這三個注解,對用戶和維護者是有益的,用戶可以立即看出來這個類是否是線程安全的,維護者則是可以根據這個注解,重點檢查線程安全方面。另外,代碼分析工具可能會利用這個注解。
2、域 Annotation(注解)
域注解是對類里面成員變量加的注解。
3、方法 Annotation(注解)
方法注解是對類里面方法加的注解。
域注解和方法注解都是用@GuardedBy( lock )來標識。里面的Lock是告訴維護者:這個狀態變量,這個方法被哪個鎖保護著。這樣可以強烈的提示類的維護者注意這里。
@GuardedBy( lock )有以下幾種使用形式:
1、@GuardedBy( "this" ) 受對象內部鎖保護
2、@GuardedBy( "fieldName" ) 受 與fieldName引用相關聯的鎖保護。
3、@GuardedBy( "ClassName.fieldName" ) 受 一個類的靜態field的鎖保存。
4、@GuardedBy( "methodName()" ) 鎖對象是 methodName() 方法的返值,受這個鎖保護。
5、@GuardedBy( "ClassName.class" ) 受 ClassName類的直接鎖對象保護。而不是這個類的某個實例的鎖對象。
八、servlet3.0的注解
在最新的servlet3.0中引入了很多新的注解,尤其是和servlet安全相關的注解。
HandlesTypes?–該注解用來表示一組傳遞給ServletContainerInitializer的應用類。
HttpConstraint?– 該注解代表所有HTTP方法的應用請求的安全約束,和ServletSecurity注釋中定義的HttpMethodConstraint安全約束不同。
HttpMethodConstraint?– 指明不同類型請求的安全約束,和ServletSecurity 注解中描述HTTP協議方法類型的注釋不同。
MultipartConfig?–該注解標注在Servlet上面,表示該Servlet希望處理的請求的 MIME 類型是 multipart/form-data。
ServletSecurity?該注解標注在Servlet繼承類上面,強制該HTTP協議請求遵循安全約束。
WebFilter?– 該注解用來聲明一個Server過濾器;
WebInitParam?– 該注解用來聲明Servlet或是過濾器的中的初始化參數,通常配合 @WebServlet 或者 @WebFilter 使用。
WebListener?–該注解為Web應用程序上下文中不同類型的事件聲明監聽器。
WebServlet?–該注解用來聲明一個Servlet的配置。
總結
以上是生活随笔為你收集整理的Annotation之一:Java Annotation基本功能介绍的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 祝玉闪大夫治疗手抖怎么样
- 下一篇: 【数据结构作业心得】4-0 二叉树