蘇勇的blog

          奮斗

          常用鏈接

          統計

          最新評論

          JAVA的內省(introspector)與反射(reflection)

          反射

          相對而言,反射比內省更容易理解一點。用一句比較白的話來概括,反射就是讓你可以通過名稱來得到對象 ( 類,屬性,方法 ) 的技術。例如我們可以通過類名來生成一個類的實例;知道了方法名,就可以調用這個方法;知道了屬性名就可以訪問這個屬性的值。

          還是寫兩個例子讓大家更直觀的了解反射的使用方法:

          // 通過類名來構造一個類的實例
          Class cls_str = Class.forName( "java.lang.String" );
          // 上面這句很眼熟,因為使用過 JDBC 訪問數據庫的人都用過 J
          Object str = cls_str.newInstance();
          // 相當于 String str = new String();

          // 通過方法名來調用一個方法
          String methodName = "length" ;
          Method m = cls_str.getMethod(methodName, null );
          System.out.println( "length is " + m.invoke(str, null ));
          // 相當于 System.out.println(str.length());

          上面的兩個例子是比較常用方法。看到上面的例子就有人要發問了:為什么要這么麻煩呢?本來一條語句就完成的事情干嗎要整這么復雜?沒錯,在上面的例子中確實沒有必要這么麻煩。不過你想像這樣一個應用程序,它支持動態的功能擴展,也就是說程序不重新啟動但是可以自動加載新的功能,這個功能使用一個具體類來表示。首先我們必須為這些功能定義一個接口類,然后我們要求所有擴展的功能類必須實現我指定的接口,這個規定了應用程序和可擴展功能之間的接口規則,但是怎么動態加載呢?我們必須讓應用程序知道要擴展的功能類的類名,比如是 test.Func1 ,當我們把這個類名 ( 字符串 ) 告訴應用程序后,它就可以使用我們第一個例子的方法來加載并啟用新的功能。這就是類的反射,請問你有別的選擇嗎?

                 關于方法的反射建議大家看我的另外一篇文章《 利用 Turbine 的事件映射來擴展 Struts 的功能 》,地址是: http://www.javayou.com/article/CSDN/extend_struts.html 。這篇文章詳細介紹了如果通過反射來擴展 Struts 框架的功能。

          內省

          內省是 Java 語言對 Bean 類屬性、事件的一種缺省處理方法。例如類 A 中有屬性 name, 那我們可以通過 getName,setName 來得到其值或者設置新的值。通過 getName/setName 來訪問 name 屬性,這就是默認的規則。 Java 中提供了一套 API 用來訪問某個屬性的 getter/setter 方法,通過這些 API 可以使你不需要了解這個規則(但你最好還是要搞清楚),這些 API 存放于包 java.beans 中。

          一般的做法是通過類 Introspector 來獲取某個對象的 BeanInfo 信息,然后通過 BeanInfo 來獲取屬性的描述器( PropertyDescriptor ),通過這個屬性描述器就可以獲取某個屬性對應的 getter/setter 方法,然后我們就可以通過反射機制來調用這些方法。下面我們來看一個例子,這個例子把某個對象的所有屬性名稱和值都打印出來:

          /* 
           * Created on 2004-6-29
           */

          package demo;

          import java.beans.BeanInfo;
          import java.beans.Introspector;
          import java.beans.PropertyDescriptor;

          /**
            * 內省演示例子
            * @author liudong
            */

          public class IntrospectorDemo {
              String name;
              public static void main(String[] args) throws Exception{
                  IntrospectorDemo demo = new IntrospectorDemo();
                  demo.setName( "Winter Lau" );        

                  // 如果不想把父類的屬性也列出來的話,
                  // 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 ));
                  }

              }    

              public String getName() {
                  return name;
              }

              public void setName(String name) {
                  this .name = name;
              }

           

          //通過傳入一個對象,和一個屬性名字,以及用于替換的新的屬性值,修改該對象的屬性值
          private static void setProperty(Object mybean, String propertyName,
             Object newVal) throws IntrospectionException,
             IllegalAccessException, InvocationTargetException {
            PropertyDescriptor proDescriptor2=new PropertyDescriptor(propertyName,mybean.getClass());
            Method methodSetName=proDescriptor2.getWriteMethod();
            methodSetName.invoke(mybean,newVal);
           }

           private static Object getProperty(Object mybean, String propertyName)
             throws IntrospectionException, IllegalAccessException,
             InvocationTargetException {
            PropertyDescriptor proDescriptor=new PropertyDescriptor(propertyName,mybean.getClass());
            Method methodGetName=proDescriptor.getReadMethod();
            Object reVal=methodGetName.invoke(mybean);
            return reVal;
           }

           private static Object getProperty1(Object mybean, String propertyName)throws Exception {
            BeanInfo beanInfo = Introspector.getBeanInfo(JavaBean.class);
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for(PropertyDescriptor propertyDescriptor:propertyDescriptors){
             if(propertyDescriptor.getName().equals(propertyName)){
              return propertyDescriptor.getReadMethod().invoke(mybean);
             }
            }
            return null;
           }


          }

          Web 開發框架 Struts 中的 FormBean 就是通過內省機制來將表單中的數據映射到類的屬性上,因此要求 FormBean 的每個屬性要有 getter/setter 方法。但也并不總是這樣,什么意思呢?就是說對一個 Bean 類來講,我可以沒有屬性,但是只要有 getter/setter 方法中的其中一個,那么 Java 的內省機制就會認為存在一個屬性,比如類中有方法 setMobile ,那么就認為存在一個 mobile 的屬性,這樣可以方便我們把 Bean 類通過一個接口來定義而不用去關心具體實現,不用去關心 Bean 中數據的存儲。比如我們可以把所有的 getter/setter 方法放到接口里定義,但是真正數據的存取則是在具體類中去實現,這樣可提高系統的擴展性。

          總結

          Java 的反射以及內省應用到程序設計中去可以大大的提供程序的智能化和可擴展性。有很多項目都是采取這兩種技術來實現其核心功能,例如我們前面提到的 Struts ,還有用于處理 XML 文件的 Digester 項目,其實應該說幾乎所有的項目都或多或少的采用這兩種技術。在實際應用過程中二者要相互結合方能發揮真正的智能化以及高度可擴展性。

          posted on 2009-12-21 17:29 蘇勇 閱讀(357) 評論(0)  編輯  收藏


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 锦州市| 阳江市| 丽水市| 平和县| 建瓯市| 天镇县| 彭州市| 海盐县| 嘉禾县| 成安县| 赤城县| 黄浦区| 京山县| 进贤县| 五常市| 金溪县| 牙克石市| 绥化市| 通河县| 台中县| 甘泉县| 资源县| 宜章县| 平顺县| 南宁市| 商河县| 沛县| 泾阳县| 文登市| 台东县| 宁化县| 清涧县| 孝义市| 五莲县| 毕节市| 西贡区| 肇州县| 闵行区| 土默特右旗| 富民县| 潼关县|