您當前的位置:首頁 > 收藏

這個是考點:Java反射機制

作者:由 里奧ii 發表于 收藏時間:2019-08-14

這個是考點:Java反射機制

反射的定義

JAVA反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法和屬性;這種動態獲取的資訊以及動態呼叫物件的方法的功能稱為java語言的反射機制。

要獲取一個類,必須先要獲取到該類的位元組碼檔案物件。而獲取使用的就是Class類中的方法,所以先要獲取到每一個位元組碼檔案對應的Class型別的物件。

反射就是把java類中的各種成分對映成一個個的Java物件。

反射的作用

透過反射可以使程式程式碼訪問裝載到JVM 中的類的內部資訊;

獲取已裝載類的成員變數資訊;

獲取已裝載類的方法;

獲取已裝載類的構造方法資訊;

反射的應用場景

在編譯時根本無法知道該物件或類可能屬於哪些類,程式只依靠執行時資訊來發現該物件和類的真實資訊。

Java中的兩種型別:編譯時型別/執行時型別。

// Person為p的編譯時型別,Student為p的執行時型別

Person

p

=

new

Student

();

在一些極端的情況下,外部傳入一個物件時,該物件的編譯時型別是object,但程式又需要呼叫該類的 執行時型別的方法。

解決這個問題我們在程式設計時有兩種方法解決。

我們知道傳入的是類的執行時型別,就可以使用instanceof進行判斷,再強制型別轉換,就可以使用這個類的方法和變數。

我們不知道傳入的物件的型別,也不瞭解該類的方法和屬性,程式只能靠執行時資訊來發現物件和類,這時候我們就必須使用反射。

絕大部分框架的AOP,如Spring,需要依託反射機制實現。

反射的實現

透過Class.forName

透過Class。forName()方法載入字串,就可以得到該字串做代表的Class物件。

例如:

Class<?> clazz = Class。forName(“java。lang。String”)

就可以得到String類的Class物件。值得注意的是,字串必須是類的全名,即包名+類名。

下邊的程式碼是Struts配置檔案struts。xml中的一個action的配置。

<

action

name

=

“registe”

class

=

“cn。com。gqz。struts2。RegisteAction”

>

<

result

>/

registeResult

jsp

result

>

<

result

name

=

“input”

>/

registe2

jsp

result

>

action

>

這裡的class屬性給出了一個類的全名的字串,伺服器是如何透過這個字串得到類物件的呢?就是透過反射機制RegisteAction物件的。然後再去呼叫這個類中的預設的execute()方法。

透過類名呼叫class屬性得到該類的Class物件

例如:

Class<?> clazz = String。class

也可以得到String類的Class物件。

呼叫例項的getClass()方法

例如:

Date

date

=

new

Date

();

Class

<?>

clazz

=

date

getClass

();

透過上邊的兩句程式碼就可以得到date例項的Class物件。

如果是基本型別的包裝類,則可以透過呼叫包裝類的Type屬性來獲得該包裝類的Class物件

例如:

Class

<?>

clazz

=

Integer

TYPE

無論使用哪種方法獲得了Class物件,只要得到了Class物件,下來的操作方法都是相同的。

Field[] fields = clazz。getDeclaredFields();

獲取類中定義的屬性,包括private的屬性,但是不包括從父類繼承下來的屬性。

Method[] methods = clazz。getDeclaredMethods();

獲取了類中的方法,包括private的方法,但是不包括從父類繼承下來的方法。

反射的步驟

獲取目標物件的class,一般使用Class。forName(String clazzName);

透過class物件分別獲得該型別的,建構函式,屬性,方法。

透過獲得的屬性和方法,進行進一步操作。

反射類

反射的完成依賴了Java提供的反射類,Class,Constructor(構造器),Field(屬性), Method(方法)。

Class

每一個類都有一個Class物件,每當編譯一個新類就產生一個Class物件。

Class物件對應著java。lang。Class類,如果說類是物件抽象和集合的話,那麼Class類就是對類的抽象和集合。

Class類沒有公共的構造方法,Class物件是在類載入的時候由Java虛擬機器以及透過呼叫類載入器中的 defineClass 方法自動構造的,因此不能顯式地宣告一個Class物件。

Java獲取Class的三種方式

運用.class的方式來獲取Class例項

對於基本資料型別的封裝類,還可以採用。TYPE來獲取相對應的基本資料型別的Class例項。例如,

Integer。TYPE

int。class

是等效的,都是int。

利用物件呼叫getClass()方法獲取該物件的Class例項

public

class

Test

{

public

static

void

main

String

[]

args

{

System

out

println

“第一種例項化:”

);

System

out

println

int

class

);

System

out

println

Integer

TYPE

);

System

out

println

“第二種例項化:”

);

Test

test

=

new

Test

();

System

out

println

test

getClass

()。

getName

());

System

out

println

test

getClass

()。

getSimpleName

());

}

}

使用Class類的靜態方法forName

使用Class類的靜態方法forName(),用類的名字獲取一個Class例項(static Class forName(String className) ),這種方式靈活性最高,根據類的字串全名即可獲取Class例項,可以動態載入類,框架設計經常用到。

結語

雖然反射看起來無所不能,但Java反射預設受限於Java的訪問控制。

如:無法訪問private私有的方法和欄位,Java的安全機制不允許檢視這些物件的直接值,若強制讀取則丟擲異常。

以上就是本篇全部內容,是很早的時候,在用反射機制做日誌管理的時候寫的,也是邊學邊總結,不是很全面或可能有錯誤。如果本文有任何錯誤或有什麼看法,歡迎指出。

原作者:東野啊

原文連結:這個是考點:Java反射機制

原出處:公眾號

這個是考點:Java反射機制

標簽: Class  物件  反射  獲取  方法