1. 程式人生 > >java的反射機制(備忘)

java的反射機制(備忘)

一、概述

瞭解

1.使用反射訪問方法和屬性

2.使用反射動態建立和訪問陣列

理解

1.反射的概念和應用場合

2.使用反射獲取類的資訊

3.使用反射建立物件

二、反射機制 

1、反射的概念

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

在電腦科學領域,反射是指一類應用,它們能夠自描述和自控制。

好吧,這句話太正式了,我不是很理解,然後我在網上搜了哈,參考別人的理解,就是我們可以在java程式執行時載入、探知、使用編譯期間完全未知的classes,

也就是能夠看透class的能力,就是java的反射機制。實際上說白了,之前不是說private修飾的類成員,不能被類以外的類或物件訪問嗎,而反射就可以訪問private修飾的類成員,也就是說利用java的反射機制,可以隨便的訪問類或物件的成員(不在乎它的訪問級別)和它的構造方法。


2、java反射的三個動態性質

1) 執行時生成動態物件;

2) 執行期間呼叫方法;

3) 執行時更改屬性。

3、java反射可以實現的功能

1) 在執行時判斷任意一個物件所屬的類;

2) 在執行時構造任意一個類的物件;

3) 在執行時判斷任意一個類所具有的方法和屬性;

4) 在執行時呼叫任意一個物件的方法;

5) 生成動態代理;(這個見動態代理)

4、java反射的應用場合

Java程式中許多物件在執行時都會出現兩種型別:編譯時型別執行時型別,編譯時的型別由宣告該物件時使用的型別決定,執行時的型別由實際賦給該物件的型別決定,如:


此時p的編譯時型別為Person,執行時型別為Student;因為物件p是引用型別,在編譯時其型別由Person來確定,而在程式執行後發現p引用的內容實際是Student,因為只有在程式執行的時候才能知道p引用的內容改為了Student,所以稱為執行時型別

除此之外,程式在執行時還可能接收到外部傳入的一個物件,該物件的編譯時型別是Object,但程式又需要呼叫該物件執行時型別的方法。為了解決這些問題,程式需要在執行時發現物件和類的真實資訊

。然而,如果編譯時根本無法預知該物件和類可能屬於哪些類,程式只能依靠執行時資訊來發現該物件和類的真實資訊,此時就必須使用反射

就是一句話,什麼時候用反射,就是在編譯的時候無法預知該物件和類可能屬於哪些類,程式只能依靠執行時資訊來發現該物件和類的真實資訊。這時就需要使用反射。

5、java反射API介紹

Java中用於反射的相關類都是在java.lang.reflect包中

Class類

反射的核心類,可以獲取類的屬性、方法等內容資訊

Field類

表示類的屬性,可以獲取和設定類中屬性的值

Method類

表示類的方法,它可以用來獲取類中方法的資訊,或者執行方法。

Constructor類

表示類的構造方法

Array類

Array類提供了動態建立和訪問java陣列的方法

5、使用反射機制的步驟

1) 獲得想操作的類的java.lang.Class物件;

2) 呼叫Class的方法;

3) 使用反射API來操作這些資訊;

7、獲取Class物件的方式

我們已經知道,每個類被載入後,系統就會為該類生成一個對應的Class物件,通過該Class物件就可以訪問到java虛擬機器中的這個類。Java程式中獲得Class物件通常有如下三種方式:

(1)呼叫某個物件的getClass()方法


(2)呼叫某個的class屬性來獲取該類對應的Class物件


(3)使用Class類的forName()靜態方法


注:(2)和(3)都是根據類來取得該類的Class物件,但相比之下,呼叫某個類的class屬性來獲取該類對應的Class物件這種方式有如下兩種優勢:

² 程式碼更安全,程式在編譯階段就可以檢查需要訪問的class物件是否存在;

² 程式效能更高,因為這種方式無需呼叫方法,所以程式的效能更好。


一般情況下,我們都選擇.class來獲取類,但如果我們只有一個表示類的全名的字串,而我們不知道這個字串的具體內容,此時,我們只能使用Class類的forName()方法來獲取該字串對應的Class物件。不過在使用Class類的forName()方法獲取Class物件時,該方法可能會丟擲一個ClassNotFoundException異常。


8、從Class類中獲取資訊

(1)訪問Class對應的類所包含的構造方法





(2)訪問Class對應的類所包含的方法

方法1

Method getMethod(String name,Class[] params)

返回此Class物件所表示的類的指定的public方法,name引數用於指定方法名稱,params引數是按宣告順序標識該方法引數型別的Class物件的一個數組。

例:c.getMethod(“info”,String.class);

    c.getMethod(“info”,String.class,Integer.class);


方法2

Method[] getMethods();

返回此Class物件所表示的類的所有public方法。

方法3

Method getDeclaredMethod(String name,Class[]params);

返回此Class物件所表示的類的指定的方法,與方法的訪問級別無關。

方法4

Method[] getDeclaredMethods();

返回此Class物件所表示的類的全部方法,與方法的訪問級別無關。

(3)訪問Class對應的類所包含的屬性

方法1

Field getField(String name);

返回此Class物件所表示的類的指定的public屬性,name引數用於指定屬性名稱。

例:

c.getField(“age”);


方法2

Field[] getFields();

返回此Class物件所表示的類的所有public 屬性。

方法3

Field getDeclaredField(String name);

返回此Class物件所表示的類的指定屬性,與屬性的訪問級別無關。

Field[] getDeclaredFields();

返回此Class物件所表示的類的全部屬性,與屬性的訪問級別無關。

(4)訪問Class對應的類所包含的註釋

<A extends Annotation>A getAnnotation(Class<A> annotationClass)

:試圖獲取該Class物件所表示類上指定型別的註釋;如果該型別的註釋不存在則返回null。其中annotationClass引數對應於註釋型別的Class物件。

Annotation[] getAnnotations();返回此元素上存在的所有註釋

Annotation[] getDeclaredAnnotations();返回直接存在於此元素上的所有註釋。

(5)訪問Class對應的類所包含的內部類

Class[] getDeclaredClasses();

返回該Class物件所對應類裡包含的全部內部類

(6)訪問Class對應的類所在的外部類

Class getDeclaringClass();

返回該Class物件所在的外部類

(7)訪問該Class物件所對應類所繼承的父類、所實現的介面等

int getModifiers();——返回此類或介面的所有修飾符

Class[] getInterfaces();——返回該Class物件對應類所實現的全部介面

Package getPackage();——獲取此類的包

String getName();——以字串形式返回此Class物件所表示的類的名稱

String getSimpleName();——以字串形式返回此Class物件所表示的類的簡

Class getSuperclass();——返回該Class所表示的類的超類對應的Class物件

9、建立物件


通過反射來生成物件,有如下兩種方式

(1) 使用newInstance()建立物件

這種方式要求該Class物件的對應類有預設構造方法,而執行newInstance()方

法時實際上是利用預設構造方法來建立該類的例項

(2) 使用Constructor物件建立物件

要先使用Class物件獲取指定的Constructor物件,再呼叫Constructor物件的

newInstance()方法來建立該Class物件對應類的例項。通過這種方式可以選擇

使用某個類的指定構造方法來建立例項。

反射技術多用於框架及基礎平臺中,例如Spring

如果我們不想利用預設構造方法來建立java物件,而想利用指定的構造方法來

建立Java物件,則需要利用Constructor物件了,每個Constructor對應一個

構造方法,利用指定構造方法來建立java物件需要三個步驟:

獲取該類的Class物件;

利用Class物件的getConstructor()方法來獲取指定構造方法;

呼叫Constructor的newInstance()方法來建立Java物件。


注:在java中,無論生成某個類的多少個物件,這些物件都會對應於同一個Class

物件,要想使用反射,首先需要獲得待處理類或物件所對應的Class物件。