Java動態程序設計反射介紹 使用運行的類的信息使你的程序設計更加靈活
反射授予了你的代碼訪問裝載進JVM內的Java類的內部信息的權限
並且允許你編寫在程序執行期間與所選擇的類的一同工作的代碼
而不是在源代碼中
這種機制使得反射成為創建靈活的應用程序的強大工具
但是要小心的是
如果使用不恰當
反射會帶來很大的副作用
在這篇文章中
軟件咨詢顧問Dennis Sosnoski 介紹了反射的使用
同時還介紹了一些使用反射所要付出的代價
在這裡
你可以找到Java反射API是如何在運行時讓你鉤入對象的
在第一部分
我向你介紹了Java程序設計的類以及類的裝載
那篇文章中描述了很多出現在Java二進制類格式中的信息
現在我來介紹在運行時使用反射API訪問和使用這些信息的基礎
為了使那些已經了解反射基礎的開發人員對這些事情感興趣
我還會介紹一些反射與直接訪問的在性能方面的比較
使用反射與和metadata(描述其它數據的數據)一些工作的Java程序設計是不同的
通過Java語言反射來訪問的元數據的特殊類型是在JVM內部的類和對象的描述
反射使你可以在運行時訪問各種類信息
它甚至可以你讓在運行時讀寫屬性字段
調用所選擇的類的方法
反射是一個強大的工具
它讓你建立靈活能夠在運行時組裝的代碼
而不需要連接組件間的源代碼
反射的一些特征也帶來一些問題
在這章中
我將會探究在應用程序中不打算使用反射的原因
以為什麼使用它的原因
在你了解到這些利弊之後
你就會在好處大於缺點的時候做出決定
初識class 使用反射的起點總時一個java
lang
Class類的實例
如果你與一個預先確定的類一同工作
Java語言為直接獲得Class類的實例提供了一個簡單的快捷方式
例如
Class clas = MyClass
class;
當你使用這項技術的時候
所有與裝載類有關的工作都發生在幕後
如果你需要在運行時從外部的資源中讀取類名
使用上面這種方法是不會達到目的的
相反你需要使用類裝載器來查找類的信息
方法如下所示
//
name
is the class name to load
Class clas = null;
try {
clas = Class
forName(name);
} catch (ClassNotFoundException ex) {
// handle exception case
}
// use the loaded class
如果類已經裝載
你將會找到當前在在的類的信息
如果類還沒有被裝載
那麼類裝載器將會裝載它
並且返回最近創建的類的實例
關於類的反射 Class對象給予你了所有的用於反射訪問類的元數據的基本鉤子
這些元數據包括有關類的自身信息
例如象類的包和子類
還有這個類所實現的接口
還包括這個類所定義的構造器
屬性字段以及方法的詳細信息
後面的這些項是我們在程序設計過種經常使用的
因此在這一節的後面我會給出一些用這些信息來工作的例子
對於類的構造中的每一種類型(構造器
屬性字段
方法)
java
lang
Class提供了四種獨立的反射調用以不的方式來訪問類的信息
下面列出了這四種調用的標准形式
它是一組用於查找構造器的調用
Constructor getConstructor(Class[] params) 使用指定的參數類型來獲得公共的構造器
Constructor[] getConstructors() 獲得這個類的所有構造器
Constructor getDeclaredConstructor(Class[] params) 使用指定的參數類型來獲得構造器(忽略訪問的級別)
Constructor[] getDeclaredConstructors() 獲得這個類的所有的構造器(忽略訪問的級別)
上述的每一種方法都返回一或多個java
lang
reflect
Constructor的實例
Constructor類定義了一個需要一個對象數據做為唯一參數的newInstance方法
然後返回一個最近創建的原始類的實例
對象數組是在構造器調用時所使用的參數值
例如
假設你有一個帶有一對String 類型做為參數的構造器的TwoString類
代碼如下所示
public class TwoString {
private String m_s
m_s
;
public TwoString(String s
String s
) {
m_s
= s
;
m_s
= s
;
}
}
下面的代碼顯示如何獲得TwoString類的構造器
並使用字符串
a
和
b
來創建一個實例
Class[] types = new Class[] { String
class
String
class };
Constructor cons = TwoString
class
getConstructor(types);
Object[] args = new Object[] {
a
b
};
TwoString ts = cons
newInstance(args);
上面的代碼忽略了幾種可能的被不同的反射方法拋出的異常檢查的類型
這些異常在Javadoc API中有詳細的描述
因此為簡便起見
我會在所有的代碼中忽略它們
在我涉及到構造器這個主題時
Java語言也定義了一個特殊的沒有參數的(或默認)構造器快捷方法
你能使用它來創建一個類的實例
這個快捷方法象下面的代碼這樣被嵌入到類的自定義中
Object newInstance() ?使用默認的構造器創建新的實例
盡管這種方法只讓你使用一個特殊的構造器
但是如果你需要的話
它是非常便利的快捷方式
這項技術在使用JavaBeans工作的時候尤其有用
因為JavaBeans需要定義一個公共的
沒有參數的構造器
通過反射來查找屬性字段 Class類反射調用訪問屬性字段信息與那些用於訪問構造器的方法類似
在有數組類型的參數的使用屬性字段名來替代
使用方法如下所示
Field getField(String name)
獲得由name指定的具有public級別的屬性字段
Field getFields() ?獲得一個類的所有具有public級別的屬性字段
Field getDeclaredField(String name) ?獲得由name指定的被類聲明的屬性字段
Field getDeclaredFields() ?獲得由類定義的所有的屬性字段
盡管與構造器的調用很相似
但是在提到屬性字段的時候
有一個重要的差別
前兩個方法返回能過類來訪問的公共(public)屬性字段的信息(包括那些來自於超類的屬性字段)
後兩個方法返回由類直接聲明的所有的屬性字段(忽略了屬性字段的訪問類型)
Java
lang
reflect
Field的實例通過調用定義好的getXXX和setXXX方法來返回所有的原始的數據類型
就像普通的與對象引用一起工作的get和set方法一樣
盡管getXXX方法會自動地處理數據類型轉換(例如使用getInt方法來獲取一個byte類型的值)
但使用一個適當基於實際的屬性字段類型的方法是應該優先考慮的
下面的代碼顯示了如何使用屬性字段的反射方法
通過指定屬性字段名
找到一個對象的int類型的屬性字段
並給這個屬性字段值加
public int incrementField(String name
Object obj) throws
{
Field field = obj
getClass()
getDeclaredField(name);
int value = field
getInt(obj) +
;
field
setInt(obj
value);
return value;
}
這個方法開始展現一些使用反射所可能帶來的靈活性
它優於與一個特定的類一同工作
incrementField方法把要查找的類信息的對象傳遞給getClass方法
然後直接在那個類中查找命名的屬性字段
通過反射來查找方法 Class反射調用訪問方法的信息與訪問構造器和字段屬性的方法非常相似
Method getMethod(String name
Class[] params)
使用指定的參數類型獲得由name參數指定的public類型的方法
Mehtod[] getMethods()?獲得一個類的所有的public類型的方法
Mehtod getDeclaredMethod(String name
Class[] params)?使用指定的參數類型獲得由name參數所指定的由這個類聲明的方法
Method[] getDeclaredMethods() ?獲得這個類所聲明的所有的方法
與屬性字段的調用一樣
前兩個方法返回通過這個類的實例可以訪問的public類型的方法?包括那些繼承於超類的方法
後兩個方法返回由這個類直接聲明的方法的信息
而不管方法的訪問類型
通過調用返回的Java
lang
reflect
Mehtod實例定義了一個invoke方法
你可以使用它來調用定義類的有關實例
這個invoke方法需要兩個參數
一個是提供這個方法的類的實例
一個是調用這個方法所需要的參數值的數組
下面給出了比屬性字段的例子更加深入的例子
它顯示了一個的方法反射的例子
這個方法使用get和set方法來給JavaBean定義的int類型的屬性做增量操作
例如
如果對象為一個整數類型count屬性定義了getCount和setCount方法
那麼為了給這個屬性做增量運算
你就可以把
count
做為參數名傳遞給調用的這個方法中
示例代碼如下
public int incrementProperty(String name
Object obj) {
String prop = Character
toUpperCase(name
charAt(
)) +
name
substring(
);
String mname =
get
+ prop;
Class[] types = new Class[] {};
Method method = obj
getClass()
getMethod(mname
types);
Object result = method
invoke(obj
new Object[
]);
int value = ((Integer)result)
intValue() +
;
mname =
From:http://tw.wingwit.com/Article/program/Java/hx/201311/26154.html