1. 程式人生 > >Java 反射機制原理

Java 反射機制原理

反射的概念

反射的概念是由Smith在1982年首次提出的,主要是指程式可以訪問、檢測和修改它本身狀態或行為的一種能力。這一概念的提 出很快引發了電腦科學領域關於應用反射性的研究。它首先被程式語言的設計領域所採用,並在Lisp和麵向物件方面取得了成績。其中 LEAD/LEAD++ 、OpenC++ 、MetaXa和OpenJava等就是基於反射機制的語言。最近,反射機制也被應用到了視窗系統、作業系統和檔案系統中。

反射本身並不 是一個新概念,儘管電腦科學賦予了反射概念新的含義。在電腦科學領域,反射是指一類應用,它們能夠自描述和自控制。也就是說,這類應用通過採用某種機 制來實現對自己行為的描述(self-representation)和監測(examination),並能根據自身行為的狀態和結果,調整或修改應用 所描述行為的狀態和相關的語義。

 

 

Java中的類反射:

Reflection 是 Java 程式開發語言的特徵之一,它允許執行中的 Java 程式對自身進行檢查,或者說“自審”,並能直接操作程式的內部屬性和方法。Java 的這一能力在實際應用中用得不是很多,但是在其它的程式設計語言中根本就不存在這一特性。例如,Pascal、C 或者 C++ 中就沒有辦法在程式中獲得函式定義相關的資訊。
Reflection 是 Java 被視為動態(或準動態)語言的關鍵,允許程式於執行期 Reflection APIs 取得任何已知名稱之 class 的內部資訊,包括 package、type parameters、superclass、implemented interfaces、inner classes, outer class, fields、constructors、methods、modifiers,並可於執行期生成instances、變更 fields 內容或喚起 methods。

 

 

Java類反射中所必須的類

Java的類反射所需要的類並不多,它們分別是:Field、Constructor、Method、Class、Object,下面我將對這些類做一個簡單的說明。
Field類:提供有關類或介面的屬性的資訊,以及對它的動態訪問許可權。反射的欄位可能是一個類(靜態)屬性或例項屬性,簡單的理解可以把它看成一個封裝反射類的屬性的類。
Constructor類:提供關於類的單個構造方法的資訊以及對它的訪問許可權。這個類和Field類不同,Field類封裝了反射類的屬性,而Constructor類則封裝了反射類的構造方法。
Method類:提供關於類或介面上單獨某個方法的資訊。所反映的方法可能是類方法或例項方法(包括抽象方法)。 這個類不難理解,它是用來封裝反射類方法的一個類。
Class類:類的例項表示正在執行的 Java 應用程式中的類和介面。列舉是一種類,註釋是一種介面。每個陣列屬於被對映為 Class 物件的一個類,所有具有相同元素型別和維數的陣列都共享該 Class 物件。

 

Object類:每個類都使用 Object 作為超類。所有物件(包括陣列)都實現這個類的方法。

反射的功能

獲取一個物件的類資訊. 
獲取一個類的訪問修飾符、成員、方法、構造方法以及超類的資訊. 

呼叫一個類或者例項的方法。
檢獲屬於一個介面的常量和方法宣告. 
建立一個直到程式執行期間才知道名字的類的例項. 
獲取並設定一個物件的成員,甚至這個成員的名字是在程式執行期間才知道. 
檢測一個在執行期間才知道名字的物件的方法 

反射實現

class物件存放在Java堆中,每個class都需要被相應的類載入器載入。類要想使用,必須用類載入器載入,所以需要載入器。反射機制,不是每次都去重新反射,而是提供了cache,每次都會需要類載入器去自己的cache中查詢,如果可以查到,則直接返回該類。

Jvm如何通過類載入器載入類呢?類載入器分為BootStrap Class Loader(引導類載入器),Extensions Class Loader (擴充套件類載入器),App ClassLoader(或System Class Loader),以及Custom ClassLoader(使用者自定義類載入器)。其載入過程中會先檢查類是否被已載入,檢查順序是自底向上,從Custom ClassLoader到BootStrap ClassLoader逐層檢查,只要某個classloader已載入就視為已載入此類,保證此類只所有ClassLoader載入一次。而載入的順序是自頂向下,也就是由上層來逐層嘗試載入此類。

       在forName方法中,呼叫了ClassLoader.loadClass方法來完成類的反射。根據類載入器的特殊性,流程如下:

 

先檢查自己是否已經載入過該類,如果載入過,則直接返回該類,若沒有則呼叫父類的loadClass方法,如果父類中沒有,則執行findClass方法去嘗試載入此類,也就是我們通常所理解的片面的"反射"了。這個過程主要通過ClassLoader.defineClass方法來完成。defineClass 方法將一個位元組陣列轉換為 Class 類的例項(任何類的物件都是Class類的物件)。簡單說,在執行期間,如果我們要產生某個類的物件,Java虛擬機器(JVM)會檢查該型別的Class物件是否已被載入。如果沒有被載入,JVM會根據類的名稱找到.class檔案並載入它。一旦某個型別的Class物件已被載入到記憶體,就可以用它來產生該型別的所有物件。

================================================================================================

總結

1. 反射,是指程式可以訪問、檢測或者修改它本身狀態或行為的一種能力;反射機制允許程式在執行時獲取任意一個類自身的定義資訊;例如,可以實現動態建立類的物件、變更屬性的內容或執行特定的方法功能。從而使Java具有動態語言的特性,增強了程式的靈活性和可移植性。

2. 反射的作用。Java的反射機制主要用於實現以下功能:

  • 在執行時判斷任意一個物件屬性的型別;
  • 在執行時構造任意一個類的物件;
  • 在執行時判斷任意一個類所具有的屬性/成員變數和方法;
  • 在執行時呼叫任意一個物件的方法,甚至可以呼叫private方法;

    注意:以上功能都是在執行環境中,而不是在編譯時環境中。

3. Java反射機制API:

 

  Java語言中的反射機制提供一種動態連結程式元件的多功能方法,它允許程式建立和控制任何類的物件,無需提前硬編碼目標類。這些特性使得反射特別適用於建立以普通方式與物件協作的庫。

  • Class類:代表一個類;
  • Filed類:代表類的成員變數;
  • Method類:代表類的方法;
  • Constructor類:代表類的構造方法;
  • Array類:提供了動態建立陣列及訪問陣列元素的靜態方法。該類中的所有方法都是靜態的。

反射在效能方面會有一定的損耗,用於欄位和方法接入時反射要遠慢於直接寫程式碼。如果它作為程式執行中相對很少涉及的部分將不會造成影響,因此即使測試最壞情況下的計時圖顯示的反射操作也只耗用幾微秒。