原文鏈接:
http://developer.51cto.com/art/201003/188356.htm
很多朋友在深入的接觸Java語言後就會發現這樣兩個詞:反射和內省,之前我們已經通過實例解析了Java的反射機制,在什麼場合下應用以及如何使用?今天把這二者放在一起介紹,因爲它們二者是相輔相成的。
反射
相對而言,反射比內省更容易理解一點。用一句比較白的話來概括,反射就是讓你可以通過名稱來得到對象(類,屬性,方法)的技術。例如我們可以通過類名來生成一個類的實例;知道了方法名,就可以調用這個方法;知道了屬性名就可以訪問這個屬性的值,還是寫兩個例子讓大家更直觀的瞭解反射的使用方法:
package com.zby.jianzhioffer;
import java.lang.reflect.Method;
public class Test3 {
public static void main(String[] args) throws Exception {
Class Classcls_str = Class.forName("java.lang.String");
Object str = Classcls_str.newInstance();
String methodName = "length";
Method m = Classcls_str.getMethod(methodName, null);
System.out.println("length is:" + m.invoke(str, null));
}
}
上面的兩個例子是比較常用方法。看到上面的例子就有人要發問了:爲什麼要這麼麻煩呢?本來一條語句就完成的事情幹嗎要整這麼複雜?沒錯,在上面的例子中確實沒有必要這麼麻煩。不過你想像這樣一個應用程序,它支持動態的功能擴展,也就是說程序不重新啓動但是可以自動加載新的功能,這個功能使用一個具體類來表示。首先我們必須爲這些功能定義一個接口類,然後我們要求所有擴展的功能類必須實現我指定的接口,這個規定了應用程序和可擴展功能之間的接口規則,但是怎麼動態加載呢?我們必須讓應用程序知道要擴展的功能類的類名,比如是test.Func1,當我們把這個類名(字符串)告訴應用程序後,它就可以使用我們第一個例子的方法來加載並啓用新的功能。這就是類的反射,請問你有別的選擇嗎?
內省
內省是Java語言對Bean類屬性、事件的一種缺省處理方法。例如類A中有屬性name,那我們可以通過getName,setName來得到其值或者設置新的值。通過getName/setName來訪問name屬性,這就是默認的規則。Java中提供了一套API用來訪問某個屬性的getter/setter方法,通過這些API可以使你不需要了解這個規則,這些API存放於包java.beans中。
一般的做法是通過類Introspector來獲取某個對象的BeanInfo信息,然後通過BeanInfo來獲取屬性的描述器(PropertyDescriptor),通過這個屬性描述器就可以獲取某個屬性對應的getter/setter方法,然後我們就可以通過反射機制來調用這些方法。下面我們來看一個例子,這個例子把某個對象的所有屬性名稱和值都打印出來:
package com.zby.jianzhioffer;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
public class IntrospectorDemo {
//name的set,get方法
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static void main(String[] args) throws Exception {
IntrospectorDemo demo = new IntrospectorDemo();
demo.setName("WinterLau");
// 如果不想把父類的屬性也列出來的話,
// 那getBeanInfo的第二個參數填寫父類的信息
BeanInfo bi = Introspector.getBeanInfo(demo.getClass(), Object.class);
PropertyDescriptor[] props = bi.getPropertyDescriptors();
for (int i = 0; i < props.length; i++) {
System.out.println(props[i].getName() + "="
+ props[i].getReadMethod().invoke(demo, null));
}
}
}
Web開發框架Struts中的FormBean就是通過內省機制來將表單中的數據映射到類的屬性上,因此要求FormBean的每個屬性要有getter/setter方法。但也並不總是這樣,什麼意思呢?就是說對一個Bean類來講,我可以沒有屬性,但是只要有getter/setter方法中的其中一個,那麼Java的內省機制就會認爲存在一個屬性,比如類中有方法setMobile,那麼就認爲存在一個mobile的屬性,這樣可以方便我們把Bean類通過一個接口來定義而不用去關心具體實現,不用去關心Bean中數據的存儲。比如我們可以把所有的getter/setter方法放到接口裏定義,但是真正數據的存取則是在具體類中去實現,這樣可提高系統的擴展性。
總結
將Java的反射以及內省應用到程序設計中去可以大大的提供程序的智能化和可擴展性。有很多項目都是採取這兩種技術來實現其核心功能,例如我們前面提到的Struts,還有用於處理XML文件的Digester項目,其實應該說幾乎所有的項目都或多或少的採用這兩種技術。在實際應用過程中二者要相互結合方能發揮真正的智能化以及高度可擴展性。