Java反射機制是Java語言的一個重要特性。在學習Java反射機制前,大家應該先了解兩個概念,編譯期和運作期。
編譯期是指把源碼交給編譯器編譯成計算機可以執行的檔案的過程。在 Java 中也就是把 Java 代碼編成 class 檔案的過程。編譯期隻是做了一些翻譯功能,并沒有把代碼放在記憶體中運作起來,而隻是把代碼當成文本進行操作,比如檢查錯誤。
運作期是把編譯後的檔案交給計算機執行,直到程式運作結束。所謂運作期就把在磁盤中的代碼放到記憶體中執行起來。
Java 反射機制是在運作狀态中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調用它的任意方法和屬性;這種動态擷取資訊以及動态調用對象方法的功能稱為 Java 語言的反射機制。簡單來說,反射機制指的是程式在運作時能夠擷取自身的資訊。在 Java 中,隻要給定類的名字,就可以通過反射機制來獲得類的所有資訊。
Java 反射機制在伺服器程式和中間件程式中得到了廣泛運用。在伺服器端,往往需要根據客戶的請求,動态調用某一個對象的特定方法。此外,在 ORM 中間件的實作中,運用 Java 反射機制可以讀取任意一個 JavaBean 的所有屬性,或者給這些屬性指派。

Java 反射機制主要提供了以下功能,這些功能都位于
java.lang.reflect
包。
- 在運作時判斷任意一個對象所屬的類。
- 在運作時構造任意一個類的對象。
- 在運作時判斷任意一個類所具有的成員變量和方法。
- 在運作時調用任意一個對象的方法。
- 生成動态代理。
要想知道一個類的屬性和方法,必須先擷取到該類的位元組碼檔案對象。擷取類的資訊時,使用的就是 Class 類中的方法。是以先要擷取到每一個位元組碼檔案(.class)對應的 Class 類型的對象.
衆所周知,所有 Java 類均繼承了 Object 類,在 Object 類中定義了一個 getClass() 方法,該方法傳回同一個類型為 Class 的對象。例如,下面的示例代碼:
Class labelCls = label1.getClass(); // label1為 JLabel 類的對象
利用 Class 類的對象 labelCls 可以通路 labelCls 對象的描述資訊、JLabel 類的資訊以及基類 Object 的資訊。表 1 列出了通過反射可以通路的資訊。
類型 | 通路方法 | 傳回值類型 | 說明 |
---|---|---|---|
包路徑 | getPackage() | Package 對象 | 擷取該類的存放路徑 |
類名稱 | getName() | String 對象 | 擷取該類的名稱 |
繼承類 | getSuperclass() | Class 對象 | 擷取該類繼承的類 |
實作接口 | getlnterfaces() | Class 型數組 | 擷取該類實作的所有接口 |
構造方法 | getConstructors() | Constructor 型數組 | 擷取所有權限為 public 的構造方法 |
getDeclaredContruectors() | Constructor 對象 | 擷取目前對象的所有構造方法 | |
方法 | getMethods() | Methods 型數組 | 擷取所有權限為 public 的方法 |
getDeclaredMethods() | Methods 對象 | 擷取目前對象的所有方法 | |
成員變量 | getFields() | Field 型數組 | 擷取所有權限為 public 的成員變量 |
getDeclareFileds() | Field 對象 | 擷取目前對象的所有成員變量 | |
内部類 | getClasses() | Class 型數組 | 擷取所有權限為 public 的内部類 |
getDeclaredClasses() | Class 型數組 | 擷取所有内部類 | |
内部類的聲明類 | getDeclaringClass() | Class 對象 | 如果該類為内部類,則傳回它的成員類,否則傳回 null |
如表 1 所示,在調用 getFields() 和 getMethods() 方法時将會依次擷取權限為 public 的字段和變量,然後将包含從超類中繼承到的成員變量和方法。而通過 getDeclareFields() 和 getDeclareMethod() 隻是擷取在本類中定義的成員變量和方法。
Java 反射機制的優缺點
優點:
- 能夠運作時動态擷取類的執行個體,大大提高系統的靈活性和擴充性。
- 與 Java 動态編譯相結合,可以實作無比強大的功能。
- 對于 Java 這種先編譯再運作的語言,能夠讓我們很友善的建立靈活的代碼,這些代碼可以在運作時裝配,無需在元件之間進行源代碼的連結,更加容易實作面向對象。
缺點:
- 反射會消耗一定的系統資源,是以,如果不需要動态地建立一個對象,那麼就不需要用反射;
- 反射調用方法時可以忽略權限檢查,擷取這個類的私有方法和屬性,是以可能會破壞類的封裝性而導緻安全問題。
Java 反射機制在一般的 Java 應用開發中很少使用,即便是 Java EE 階段也很少使用。