java內省機制介紹
來源:互聯網
上載者:User
一、java內省機制介紹 內省是 Java 語言對 Bean 類屬性、事件的一種處理方法(也就是說給定一個javabean對象,我們就可以得到/調用它的所有的get/set方法)。例如類 A 中有屬性 name, 那我們可以通過 getName,setName 來得到其值或者設定新的值。通過 getName/setName 來訪問 name 屬性,這就是預設的規則。 Java 中提供了一套 API 用來訪問某個屬性的 getter/setter 方法,通過這些 API 可以使你不需要瞭解這個規則,這些 API 存放於包 java.beans 中。 一般的做法是通過類 Introspector 來擷取某個對象的 BeanInfo 資訊,然後通過 BeanInfo 來擷取屬性的描述器( PropertyDescriptor ),通過這個屬性描述器就可以擷取某個屬性對應的 getter/setter 方法,然後我們就可以通過反射機制來調用這些方法。下面我們來看一個例子,這個例子把某個對象的所有屬性名稱和值都列印出來: //定義一個javabean public class PersonBean { public String name; public String[] childname; public String[] getChildname() { return childname; } public void setChildname(String[] childname) { this.childname = childname; } public String getName() { return name; } public void setName(String name) { this.name = name; } } //定義一個測試類別,來進行一下set和get方法的調用舉例 import java.beans.BeanInfo; import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.InvocationTargetException; public class TestIntrospector { public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException, SecurityException, NoSuchMethodException, InvocationTargetException, IntrospectionException { //示範一下get方法的調用 //初始化一個javabean對象 PersonBean pb=new PersonBean(); pb.setName("kangjian"); String[] childs=new String[]{"kk","jj","nn"}; pb.setChildname(childs); //將該javabean中的屬性放入到BeanInfo中。第二個參數為截止參數,表示截止到此類之前, 不包括此類。如果不設定的話,那麼將會得到本類以及其所有父類的info。 BeanInfo bi=Introspector.getBeanInfo(pb.getClass(), Object.class); //將每個屬性的資訊封裝到一個PropertyDescriptor形成一個數組 其中包括屬性名稱字,讀寫方法,屬性的類型等等 PropertyDescriptor[] pd=bi.getPropertyDescriptors(); //示範如何get for (int i = 0; i < pd.length; i++) { if(pd[i].getPropertyType().isArray()) //getPropertyType得到屬性類型。 { //getReadMethod()得到此屬性的get方法----Method對象,然後用invoke調用這個方法 String[] result=(String[]) pd[i].getReadMethod().invoke(pb, null); System.out.println(pd[i].getName()+":");//getName得到屬性名稱字 for (int j = 0; j < result.length; j++) { System.out.println(result[j]); } } else { System.out.println(pd[i].getName()+":"+pd[i].getReadMethod().invoke(pb, null)); } } //示範一下set方法的調用 //初始化一個尚未set的javabean PersonBean pb0=new PersonBean(); //類比一個資料(資料名字和javabean的屬性名稱一致) String name="luonan"; String[] childname=new String[]{"luo","nan"}; BeanInfo bi0=Introspector.getBeanInfo(pb0.getClass(), Object.class); PropertyDescriptor[] pd0=bi0.getPropertyDescriptors(); for (int i = 0; i < pd0.length; i++) { if(pd0[i].getPropertyType().isArray()) { if(pd0[i].getName().equals("childname")); { if(pd0[i].getPropertyType().getComponentType().equals(String.class)) {//getComponentType()可以得到數群組類型的元素類型 //getWriteMethod()得到此屬性的set方法---Method對象,然後用invoke調用這個方法 pd0[i].getWriteMethod().invoke(pb0,new Object[]{childname}); } } } else { if(pd0[i].getName().equals("name")); { pd0[i].getWriteMethod().invoke(pb0,name); } } } System.out.println(pb0.getName()); String[] array=pb0.getChildname(); for (int i = 0; i < array.length; i++) { System.out.println(array[i]); } } } 更難的應用請參考 http://hi.baidu.com/shunxinyangkun/blog/item/dd2c4ff46ae61aeb7609d7ba.html 二、關於內省的思考 struts2的action(還有struts1的formbean)就是這麼實現的。 前台的form標籤具有一些屬性(在設定檔中知道這個form提交到那個action,而這個action有和這個form相對應的屬性及其 get/set),提交以後,由struts的servlet攔下來轉寄給某個具體的action.而在轉寄給action之前struts通過內省的方式將form中的值set到了action中去。 其實只要有個set**或者get**,內省就會理解為存在這樣的**屬性,這樣可以方便我們把 Bean 類通過一個介面來定義而不用去關心具體實現,不用去關心 Bean 中資料的儲存。比如我們可以把所有的 getter/setter 方法放到介面裡定義,但是真正資料的存取則是在具體類中去實現,這樣可提高系統的擴充性。 三、總結 將 Java 的反射以及內省應用到程式設計中去可以大大的提供者的智能化和可擴充性。有很多項目都是採取這兩種技術來實現其核心功能,例如我們前面提到的 Struts ,還有用於處理 XML 檔案的 Digester 項目,其實應該說幾乎所有的項目都或多或少的採用這兩種技術。在實際應用過程中二者要相互結合方能發揮真正的智能化以及高度可擴充性。 原文連結地址: http://polaris.blog.51cto.com/1146394/273614