1. 程式人生 > >java ----> 註解/反射

java ----> 註解/反射

可能 log 10個 pes 參考 cor local tps 獲得

註解

一個例子,摘自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 ----> 註解/反射