Reflection也就是反射,是Java語言的重要特徵,我們知道,在使用一個類別之前,我們往往都已經創建好它了,例如創建一個類別文件,然後再寫些屬性、方法等,也就是這種類是靜態的,但反射機制允許你動態地建立一個類別。除了動態地創建一個類別外,我們還能動態地獲取同類物件的數據,並將這些數據賦給新創建的類,這有點類似克隆複製。在很多時候,我們都需要這種動態創建類的特徵,例如在處理一些業務,但這些業務卻又稍有區別的時候,往往對應著多個類,在處理的時候,我們就要根據不同的業務處理來呼叫不同的類,這時候反射機制就派上用場了。
以下是JDK API中關於軟體包java.lang.reflect的描述:
提供類別和接口,以獲取關於類別和物件的反射資訊。在安全限制內,反射允許程式設計存取關於載入類別的欄位、方法和建構方法的信息,並允許使用反射欄位、方法和建構方法對物件上的基本對等項進行操作。
如果必需的ReflectPermission 可用,則AccessibleObject 允許抑制存取檢查。
Arrays 提供動態建立和存取陣列的靜態方法。
此套件中的類別以及java.lang.Class 可以適應以下應用程式的需要:偵錯程式、解釋程式、物件檢查程式、類別瀏覽程序,以及服務(例如,Object Serialization 和JavaBean,它們需要存取目標物件(基於其運行時類別)的公共成員或給定類別聲明的成員)。
下面透過兩個簡單範例來說明反射的用法,先建立一個Person類別:
複製代碼代碼如下:
package test;
public class Person {
private int age;
private String name = "";
private String[] arr = new String[2];
public Person(){}
public Person(String name,int age){
this.name = name;
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String[] getArr() {
return arr;
}
public void setArr(String[] arr) {
this.arr = arr;
}
}
實例1:得到Person類別的屬性及方法資訊複製程式碼代碼如下:
private static void testSimpleReflect(){
String className = "test.Person";
try {
Class c = Class.forName(className);
Field[] fields = c.getDeclaredFields();
Method[] m = c.getDeclaredMethods();
for (Field field : fields){
System.out.println(field.getName());
}
for (Method method : m){
System.out.println(m.getClass());
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
這種是非常簡單的,透過類別所在包路徑來得到一個類,在實際的工作中,也是使用最多的。
實例2:物件複製複製程式碼如下:
@SuppressWarnings("unchecked")
public static Object copy(Object object) throws Exception {
// 取得物件類型
Class classType = object.getClass();
System.out.println("" + classType.getName()); // 透過預設建構方法建立一個新的對象
Object objectCopy = classType.getConstructor(new Class[] {})
.newInstance(new Object[] {}); // 取得物件的所有屬性
Field fields[] = classType.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
String fieldName = field.getName();
String firstLetter = fieldName.substring(0, 1).toUpperCase(); // 取得和屬性對應的getXXX()方法的名字
String getMethodName = "get" + firstLetter + fieldName.substring(1); // 取得和屬性對應的setXXX()方法的名字
String setMethodName = "set" + firstLetter + fieldName.substring(1); // 取得與屬性對應的getXXX()方法
Method getMethod = classType.getMethod(getMethodName,
new Class[] {}); // 取得和屬性對應的setXXX()方法
Method setMethod = classType.getMethod(setMethodName,
new Class[] { field.getType() }); // 呼叫原始物件的getXXX()方法
Object value = getMethod.invoke(object, new Object[] {});
System.out.println(fieldName + ":" + value); // 呼叫拷貝物件的setXXX()方法
setMethod.invoke(objectCopy, new Object[] { value });
}
return objectCopy;
}
利用反射來實現物件的複製,我們通常不用自己這麼乾,因為開源系統BeanUtils已經替我們做好物件拷貝的封裝了,我們直接呼叫它的方法即可,但值得注意的是,BeanUtils也是基於反射機制來做的封裝
下面是一調用:
複製代碼代碼如下:
public static void main(String[] args){
Person person = new Person("tom",22);
String[] strs = new String[]{"a","b"};
person.setArr(strs);
try {
Person p = (Person)copy(person);
System.out.println(p.getName()+">>"+p.getAge());
for (String str : p.getArr()){
System.out.println(str);
}
} catch (Exception e) {
e.printStackTrace();
}
// testSimpleReflect();
}