您當前的位置:首頁 > 動漫

java反射原來是這麼玩的(反射一開,誰都不愛)

作者:由 java之旅 發表于 動漫時間:2022-08-27

反射的發展歷史

1996年01月23日,jdk 1。0版本釋出,代號為Oak(橡樹)。

這個代號為Oak(橡樹)的版本,在釋出後的第二年,1997年02月19日,釋出jdk 1。1版本,這次版本釋出中引入了

反射

機制。

關於反射機制,由於年代久遠,能搜尋到對於反射機制的記載少之又少,能找到最為久遠的是一篇題為《Using Java Reflection》的文章,發表於 1998年1月,文中提到:

反射是一個可以獲取java類、屬性的一個工具,因為它是動態載入的

而在另外一篇文章《A Button is a Bean》裡解釋道,反射是為了能把一個類的屬性視覺化的展示給使用者,如下圖所示:

java反射原來是這麼玩的(反射一開,誰都不愛)

通俗的解釋就是:無論是公有還是私有的方法、屬性、構造方法,全都可以用反射進行獲取、進行賦值、呼叫。聽到這個解釋,是不是感覺反射很強。

正因為反射的強大,在java世界裡運用的地方有很多,比如:Java類載入和初始化、Java中RTTI、Spring的IOC,。

如此廣泛的運用,只能說反射除了強,用起來肯定很爽。我想起我的同事,IT界的刁民,總是熱衷於反射。

他在講解他是如何運用反射時,嘴角總是壓抑不住的微笑,這種迷戀反射的樣子,像極了愛情。

正所謂:

反射一開,誰都不愛

下面就看看反射究竟是如何在程式中使用的。

反射的概述和使用

反射的概述

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

我們知道class檔案是在編譯的時候生成的,Class物件是將class檔案讀入記憶體,併為之建立一個Class物件。

Class 沒有公共構造方法。Class 物件是在載入類時由 Java 虛擬機器以及透過呼叫類載入器中的defineClass 方法自動構造的。也就是這不需要我們自己去處理建立,JVM已經幫我們建立好了。

Class類裡面,包含了一個類應有的所有描述,包括: 欄位:Field。java 方法:Method。java 構造方法:Constructor。java 等等。。。

知道了Class類裡面包含了哪些內容之後,再看一下new一個物件的究竟會發生那些過程:

java反射原來是這麼玩的(反射一開,誰都不愛)

反射的使用

這裡使用一個Animal類來作為示範,可以看到這個類裡的成員變數、方法、構造方法的訪問修飾符既有public、也有private的。下面就將使用反射獲取不同修飾符修飾的成員變數、方法、構造方法。

package

com。shuai。ioc。ref

public

class

Animal

{

/**

* 動物名字

*/

public

String

name

/**

* 動物年齡

*/

protected

int

age

@Override

public

String

toString

()

{

return

“Animal{”

+

“name=‘”

+

name

+

’\‘’

+

“, age=”

+

age

+

‘}’

}

/**

* 預設的構造方法

*

* @param name

*/

Animal

String

name

{

System

out

println

“執行了”

+

“預設的構造方法 ”

+

name

);

}

/**

* 無參構造方法

*/

public

Animal

()

{

System

out

println

“執行了”

+

“無參構造方法 ”

);

}

/**

* 有一個引數的構造方法

*

* @param name

*/

public

Animal

char

name

{

System

out

println

“執行了”

+

“有一個引數的構造方法 name:”

+

name

);

}

/**

* 有多個引數的構造方法

*

* @param name

* @param age

*/

public

Animal

String

name

int

age

{

System

out

println

“執行了”

+

“有多個引數的構造方法 name:”

+

name

+

“age:”

+

age

);

}

/**

* protected的構造方法

*

* @param n

*/

protected

Animal

boolean

n

{

System

out

println

“執行了”

+

“受保護的構造方法 n:”

+

n

);

}

/**

* 私有構造方法

*

* @param age

*/

private

Animal

int

age

{

System

out

println

“執行了”

+

“私有構造方法 age:”

+

age

);

this

name

=

“私有構造方法呼叫成功”

this

age

=

age

}

/**

* 公有方法

*

* @param s

*/

public

void

public1

String

s

{

System

out

println

“呼叫了”

+

“公有的方法”

+

“: public1 , s:”

+

s

);

}

/**

* protected的方法

*/

protected

void

protected2

()

{

System

out

println

“呼叫了”

+

“protected的方法”

+

“: protected2 ”

);

}

/**

* 友好的方法

*/

void

friendly1

()

{

System

out

println

“呼叫了”

+

“友好的方法”

+

“: friendly1 ”

);

}

/**

* 私有方法

*

* @param age

* @return

*/

private

String

private1

int

age

{

System

out

println

“呼叫了”

+

“私有方法”

+

“: private1 ,age:”

+

age

);

return

age

+

“”

}

}

用反射獲取類的構造方法

在Class類中,提供一系列獲取被反射類構造方法的方法。

批次獲取構造方法的方法

public Constructor[] getConstructors()

:所有“公有的”構造方法

public Constructor[] getDeclaredConstructors()

:獲取所有的構造方法(包括私有、受保護、預設、公有)

獲取單個的方法,並呼叫

public Constructor getConstructor(Class。。。 parameterTypes)

:獲取單個的“公有的”構造方法

public Constructor getDeclaredConstructor(Class。。。 parameterTypes)

:獲取“某個構造方法”可以是私有的,或受保護、預設、公有;

呼叫構造方法

newInstance(Object。。。 initargs)

package

com。shuai。ioc。ref

import

com。shuai。ioc。Book

import

java。lang。reflect。Constructor

public

class

ConstructorsTest

{

public

static

void

main

String

[]

args

throws

Exception

{

//1。載入Class物件

Class

clazz

=

Class

forName

“com。shuai。ioc。ref。Animal”

);

//2。獲取所有公有構造方法

System

out

println

“所有公有構造方法”

);

Constructor

[]

conArray

=

clazz

getConstructors

();

for

Constructor

c

conArray

{

System

out

println

c

);

}

// 所有的構造方法,公有、私有都行

System

out

println

“”

);

System

out

println

“所有的構造方法,包括:私有、受保護、預設、公有”

);

conArray

=

clazz

getDeclaredConstructors

();

for

Constructor

c

conArray

{

System

out

println

c

);

}

// 獲取公有、無參的構造方法

System

out

println

“”

);

System

out

println

“獲取公有、無參的構造方法”

);

Constructor

con

=

clazz

getConstructor

null

);

System

out

println

“con = ”

+

con

);

//呼叫構造方法

Object

obj

=

con

newInstance

();

// 獲取私有構造方法

System

out

println

“”

);

System

out

println

“獲取私有構造方法,並呼叫”

);

con

=

clazz

getDeclaredConstructor

int

class

);

System

out

println

con

);

//暴力訪問,忽略掉訪問修飾符

con

setAccessible

true

);

//呼叫構造方法

Animal

animal

=

Animal

con

newInstance

1

);

System

out

println

animal

toString

());

}

}

用反射獲取類的方法

在Class類中,提供一系列獲取被反射類構造方法的方法。

批次的

public Method[] getMethods()

:獲取所有“公有方法”;(包含了父類的方法也包含Object類)

public Method[] getDeclaredMethods()

:獲取所有的成員方法,包括私有的(不包括繼承的)

獲取單個的

public Method getMethod(String name,Class<?>。。。 parameterTypes)

name

: 方法名;

Class 。。。

:形參的Class型別物件

public Method getDeclaredMethod(String name,Class<?>。。。 parameterTypes)

obj

:要呼叫方法的物件;

args

:呼叫方式時所傳遞的實參;

呼叫方法

public Object invoke(Object obj,Object。。。 args)

obj

:要呼叫方法的物件;

args

:呼叫方式時所傳遞的實參;

package

com。shuai。ioc。ref

import

java。lang。reflect。Method

public

class

MethodClassTest

{

public

static

void

main

String

[]

args

throws

Exception

{

//1。獲取Class物件

Class

stuClass

=

Class

forName

“com。shuai。ioc。ref。Animal”

);

//2。獲取所有公有方法

System

out

println

“獲取所有 公有 方法”

);

stuClass

getMethods

();

Method

[]

methodArray

=

stuClass

getMethods

();

for

Method

m

methodArray

{

System

out

println

m

);

}

System

out

println

();

System

out

println

“獲取所有的方法,包括私有的”

);

methodArray

=

stuClass

getDeclaredMethods

();

for

Method

m

methodArray

{

System

out

println

m

);

}

System

out

println

();

System

out

println

“獲取公有的public1()方法”

);

Method

m

=

stuClass

getMethod

“public1”

String

class

);

System

out

println

m

);

//例項化一個Student物件

Object

obj

=

stuClass

getConstructor

()。

newInstance

();

m

invoke

obj

“this is name value”

);

System

out

println

();

System

out

println

“獲取私有的private1()方法”

);

m

=

stuClass

getDeclaredMethod

“private1”

int

class

);

System

out

println

m

);

m

setAccessible

true

);

//解除私有限定

Object

result

=

m

invoke

obj

20

);

//需要兩個引數,一個是要呼叫的物件(獲取有反射),一個是實參

System

out

println

“返回值:”

+

result

);

}

}

用反射獲取類的欄位

在Class類中,提供一系列獲取被反射類構造方法的方法。

批次的

Field[] getFields()

:獲取所有的“公有欄位”

Field[] getDeclaredFields()

:獲取所有欄位,包括:私有、受保護、預設、公有;

獲取單個的

public Field getField(String fieldName)

:獲取某個“公有的”欄位;

public Field getDeclaredField(String fieldName)

:獲取某個欄位(可以是私有的)

設定欄位的值

public void set(Object obj,Object value)

obj

:要設定的欄位所在的物件;

value

:要為欄位設定的值;

package

com。shuai。ioc。ref

import

java。lang。reflect。Field

public

class

FieldsTest

{

public

static

void

main

String

[]

args

throws

Exception

{

//1。獲取Class物件

Class

animalClass

=

Class

forName

“com。shuai。ioc。ref。Animal”

);

//2。獲取欄位

System

out

println

“獲取所有公有的欄位”

);

Field

[]

fieldArray

=

animalClass

getFields

();

for

Field

f

fieldArray

{

System

out

println

f

);

}

System

out

println

();

System

out

println

“獲取所有的欄位(包括私有、受保護、預設的)”

);

fieldArray

=

animalClass

getDeclaredFields

();

for

Field

f

fieldArray

{

System

out

println

f

);

}

System

out

println

();

System

out

println

“獲取公有欄位並呼叫”

);

Field

f

=

animalClass

getField

“name”

);

System

out

println

f

);

//獲取一個物件

Object

obj

=

animalClass

getConstructor

()。

newInstance

();

//產生Student物件——》Student stu = new Student();

//為欄位設定值

f

set

obj

“dog”

);

//為Student物件中的name屬性賦值——》stu。name = “劉德華”

//驗證

Animal

stu

=

Animal

obj

System

out

println

“驗證name:”

+

stu

name

);

System

out

println

();

System

out

println

“獲取私有欄位並呼叫”

);

f

=

animalClass

getDeclaredField

“name”

);

System

out

println

f

);

f

setAccessible

true

);

//暴力反射,解除私有限定

f

set

obj

“this is name value”

);

System

out

println

“驗證name:”

+

stu

);

}

}

反射越過泛型檢查

編寫程式碼時,如果我們設定容器list為String型別,在呼叫add方法插入資料時入參傳了其他型別,編譯時會無法成功,但是透過反射卻可以執行,例項程式碼:

package

com。shuai。ioc。ref

import

java。lang。reflect。Method

import

java。util。ArrayList

import

java。util。List

/*

* 透過反射越過泛型檢查

*

*/

public

class

IgnoreType

{

public

static

void

main

String

[]

args

throws

Exception

{

List

<

String

>

list

=

new

ArrayList

<>();

list

add

“one”

);

//反射獲取list物件

Class

listClass

=

list

getClass

();

// 呼叫list物件的add方法

Method

m

=

listClass

getMethod

“add”

Object

class

);

m

invoke

list

100

);

//輸出驗證

for

Object

obj

list

{

System

out

println

obj

);

}

}

}

歡迎關注我的公眾號:java之旅。

標簽: System  out  println  構造方法  獲取