java ----> 註解/反射
註解
一個例子,摘自Junit-4.12.jar源碼。
1 @Retention(RetentionPolicy.RUNTIME)
2 @Target({java.lang.annotation.ElementType.METHOD})
3 public @interface Test{
4
5 //......
6 }
關註兩個元註解和兩個類,它們位於java.lang.annotation包中。
@Retention(RetentionPolicy.RUNTIME)
@Target(java.lang.annotation.ElementType.METHOD)
1、@Retention和RetentionPolicy
@Retention
表示要保留帶註釋類型的註釋的時間長度。可以理解為註解的生命周期。 如果註釋類型聲明中不存在Retention註釋,則保留策略默認為RetentionPolicy.CLASS。
RetensionPolicy
註釋保留策略。RetensionPolicy是一個枚舉類型的類。 此枚舉類型的常量描述了用於保留註釋的各種策略。 它們與Retention元註釋類型結合使用,以指定保留註釋的時間。有三個枚舉類型的常量,分別是SOURCE,CLASS,RUNTIME。它們分別對應java源文件階段,class文件階段,內存中的字節碼階段。(參考博客:https://www.cnblogs.com/xdp-gacl/p/3622275.html)
SOURCE:表示編譯器會丟棄註解。
CLASS:這是默認的保留策略。表示編譯器會在類文件中記錄註解,但是在運行時VM不會保留註解。
RUNTIME:表示編譯器會在類文件中記錄註解,並且在運行時VM會保留註解。可以通過反射技術讀取註解。
2、@Target和ElementType
@Target
表示註釋類型可用的上下文環境。
ElementType
元素類型。ElementType是一個枚舉類型的類。描述了註解在java編程中可能出現的語法位置。 它們與Target元註釋類型結合使用,以指定給定類型的註解的合法位置。有10個枚舉類型的常量,分別是TYPE、FIELD、METHOD、PARAMETER、CONSTRUCTOR、LOCAL_VARIABLE、ANNOTATION_TYPE、PACKAGE、TYPE_PARAMETER、TYPE_USE
TYPE:類,接口(包括註解),枚舉聲明
FIELD:字段(包括枚舉的常量)聲明
METHOD:方法聲明
PARAMETER:格式化參數聲明
CONSTRUCTOR:構造器聲明
LOCAL_VARIABLE:局部變量聲明
ANNOTATION_TYPE:註解類型聲明
PACKAGE:包聲明
定義一個註解
1 public @interface FirstAnnotation{}
註解的本質
註解是一個特殊的類,更像是一個接口。
註解和反射的關系
說明:ClassName表示某個類的名稱;AnnotationName表示某個註解的名稱。
通過反射技術可以獲取註解的信息。
獲取註解:Method#getAnnotation(AnnotationName.class)
或者:ClassName.class.getAnnotation(AnnotationName.class)
檢查註解是否存在:ClassName.class.isAnnotationPresent(AnnotationName.class)
反射
1、反射:在運行狀態中,動態獲取對象的信息或者動態調用對象的方法的技術。
2、RTTI(run-time type identification),運行時類型識別,在運行時識別一個對象的類型和類的信息。兩種方式:編譯期已經知道所有類型;通過反射機制在運行時獲取類型的信息。
3、Class:java中獲取運行時類型信息的類。
Class對象的作用:為Java虛擬機(JVM)創建實例對象或者提供靜態變量的引用值的媒介。Class對象由類加載器子系統加載到JVM中。Class對象是被按需加載的。
獲取Class對象的方式:
1)、Class.forName("...")
2)、ClassName.class,不會觸發類的初始化
3)、obj.getClass()
4、類的加載過程:
加載 -> 鏈接(驗證->準備->解析)->初始化
加載:已加載字節碼文件,可通過它創建Class對象
鏈接:
驗證:安全性和完整性
準備:為靜態變量分配空間
解析:處理類中的其他所有引用
初始化:對超類初始化和靜態變量,靜態代碼塊等初始化。
5、關註一個類和一個類庫:
java.lang.Class
方法:
forName("指定類的全限定名") // 獲取Class對象的引用
newInstance() // 實例化默認構造方法
①構造方法
getConstructor(指定參數類型,一個或者多個) // 獲得指定參數類型的public構造方法,只有一個
getConstructors() // 獲得所有public構造方法
getDeclaredConstructor(指定參數類型,一個或者多個) // 獲得指定參數類型的構造方法(包括private),只有一個
getDeclaredConstructors() // 獲得全部的構造方法(包括private),返回數組
②屬性
getField("指定屬性名稱") // 獲得指定名稱 的public屬性,屬性必須存在
getField() // 獲得所有public屬性,包括父類,屬性必須存在
getDeclaredField("指定屬性名稱") // 獲得指定名稱的屬性(包括private),不包含父類的屬性
getDeclaredField() //獲得所有聲明的屬性(包括private),返回數組,不包含父類的屬性
③方法
getMethod("指定方法名稱",指定參數類型) // 獲得指定方法名稱和參數類型的public方法
getMethods() // 獲得所有public方法
getDeclaredMethod("指定方法名稱") //獲得指定方法名稱的方法(包括private),不包含父類的方法
getDeclaredMethods() // 獲得所有聲明的方法(包括private),返回數組,不包含父類的方法
java.lang.reflect類庫,類庫中常用的幾個類:Constructor,Field,Method。
①Constructor
getParameterTypes() // 獲得構造方法參數類型,返回Class類型數組
getDeclaringClass() //返回Class對象,可以用過Class.getName()獲得類的全限定名
getGenericParameterTypes() // 獲得構造方法的形參類型,返回Type類型數組。
newInstance(Object... initargs) // 通過構造方法創建實例
②Field
setAccessible(true) // 設置該private屬性可以被訪問到,false表示該屬性不可被訪問到
getType() // 返回該屬性聲明的類型
getName() // 返回指定field的名字
get(Object obj) // 返回指定field的值
set(Object obj, object value) // 重新設置指定field的值
③Method
setAccessible(true) //設置該private方法可被訪問,false表示該方法不可被訪問到
invoke(Object obj,Object... args) // 調用指定方法名和參數的方法
getReturnType() // 獲得方法的返回類型
getName() // 獲得方法名稱
參考:《jdk1.8.0_172-src》《jdk1.8.0_172-docs-all》
java ----> 註解/反射