Java ?Reflection?(JAVA反射)????

          Reflection?是?Java?程序開(kāi)發(fā)語(yǔ)言的特征之一,它允許運(yùn)行中的?Java?程序?qū)ψ陨磉M(jìn)行檢查,或者說(shuō)“自審”,并能直接操作程序的內(nèi)部屬性。例如,使用它能獲得?Java?類(lèi)中各成員的名稱(chēng)并顯示出來(lái)。

          Java?的這一能力在實(shí)際應(yīng)用中也許用得不是很多,但是在其它的程序設(shè)計(jì)語(yǔ)言中根本就不存在這一特性。例如,Pascal、C?或者?C++?中就沒(méi)有辦法在程序中獲得函數(shù)定義相關(guān)的信息。

          JavaBean?是?reflection?的實(shí)際應(yīng)用之一,它能讓一些工具可視化的操作軟件組件。這些工具通過(guò)?reflection?動(dòng)態(tài)的載入并取得?Java?組件(類(lèi))?的屬性。



          1.?一個(gè)簡(jiǎn)單的例子

          考慮下面這個(gè)簡(jiǎn)單的例子,讓我們看看?reflection?是如何工作的。

          import?java.lang.reflect.*;
          public?class?DumpMethods?{
          ???public?static?void?main(String?args[])?{
          ???????try?{
          ???????????Class?c?=?Class.forName(args[0]);
          ???????????Method?m[]?=?c.getDeclaredMethods();
          ???????????for?(int?i?=?0;?i?<?m.length;?i++)
          ???????????????System.out.println(m[i].toString());
          ???????}?catch?(Throwable?e)?{
          ???????????System.err.println(e);
          ???????}
          ???}
          }

          按如下語(yǔ)句執(zhí)行:

          java?DumpMethods?java.util.Stack

          它的結(jié)果輸出為:

          public?java.lang.Object?java.util.Stack.push(java.lang.Object)

          public?synchronized?java.lang.Object?java.util.Stack.pop()

          public?synchronized?java.lang.Object?java.util.Stack.peek()

          public?boolean?java.util.Stack.empty()

          public?synchronized?int?java.util.Stack.search(java.lang.Object)

          這樣就列出了java.util.Stack?類(lèi)的各方法名以及它們的限制符和返回類(lèi)型。

          這個(gè)程序使用?Class.forName?載入指定的類(lèi),然后調(diào)用?getDeclaredMethods?來(lái)獲取這個(gè)類(lèi)中定義了的方法列表。java.lang.reflect.Methods?是用來(lái)描述某個(gè)類(lèi)中單個(gè)方法的一個(gè)類(lèi)。

          2.開(kāi)始使用?Reflection

          用于?reflection?的類(lèi),如?Method,可以在?java.lang.relfect?包中找到。使用這些類(lèi)的時(shí)候必須要遵循三個(gè)步驟:第一步是獲得你想操作的類(lèi)的?java.lang.Class?對(duì)象。在運(yùn)行中的?Java?程序中,用?java.lang.Class?類(lèi)來(lái)描述類(lèi)和接口等。

          下面就是獲得一個(gè)?Class?對(duì)象的方法之一:

          Class?c?=?Class.forName("java.lang.String");

          這條語(yǔ)句得到一個(gè)?String?類(lèi)的類(lèi)對(duì)象。還有另一種方法,如下面的語(yǔ)句:

          Class?c?=?int.class;

          或者

          Class?c?=?Integer.TYPE;

          它們可獲得基本類(lèi)型的類(lèi)信息。其中后一種方法中訪(fǎng)問(wèn)的是基本類(lèi)型的封裝類(lèi)?(如?Integer)?中預(yù)先定義好的?TYPE?字段。

          第二步是調(diào)用諸如?getDeclaredMethods?的方法,以取得該類(lèi)中定義的所有方法的列表。

          一旦取得這個(gè)信息,就可以進(jìn)行第三步了??使用?reflection?API?來(lái)操作這些信息,如下面這段代碼:

          Class?c?=?Class.forName("java.lang.String");

          Method?m[]?=?c.getDeclaredMethods();

          System.out.println(m[0].toString());

          它將以文本方式打印出?String?中定義的第一個(gè)方法的原型。

          在下面的例子中,這三個(gè)步驟將為使用?reflection?處理特殊應(yīng)用程序提供例證。

          模擬?instanceof?操作符

          得到類(lèi)信息之后,通常下一個(gè)步驟就是解決關(guān)于?Class?對(duì)象的一些基本的問(wèn)題。例如,Class.isInstance?方法可以用于模擬?instanceof?操作符:

          class?A?{
          }

          public?class?instance1?{
          ???public?static?void?main(String?args[])?{
          ???????try?{
          ???????????Class?cls?=?Class.forName("A");
          ???????????boolean?b1?=?cls.isInstance(new?Integer(37));
          ???????????System.out.println(b1);
          ???????????boolean?b2?=?cls.isInstance(new?A());
          ???????????System.out.println(b2);
          ???????}?catch?(Throwable?e)?{
          ???????????System.err.println(e);
          ???????}
          ???}
          }

          在這個(gè)例子中創(chuàng)建了一個(gè)?A?類(lèi)的?Class?對(duì)象,然后檢查一些對(duì)象是否是?A?的實(shí)例。Integer(37)?不是,但?new?A()?是。

          3.找出類(lèi)的方法

          找出一個(gè)類(lèi)中定義了些什么方法,這是一個(gè)非常有價(jià)值也非常基礎(chǔ)的?reflection?用法。下面的代碼就實(shí)現(xiàn)了這一用法:

          import?java.lang.reflect.*;

          public?class?method1?{
          ???private?int?f1(Object?p,?int?x)?throws?NullPointerException?{
          ???????if?(p?==?null)
          ???????????throw?new?NullPointerException();
          ???????return?x;
          ???}

          ???public?static?void?main(String?args[])?{
          ???????try?{
          ???????????Class?cls?=?Class.forName("method1");
          ???????????Method?methlist[]?=?cls.getDeclaredMethods();
          ???????????for?(int?i?=?0;?i?<?methlist.length;?i++)?{
          ???????????????Method?m?=?methlist[i];
          ???????????????System.out.println("name?=?"?+?m.getName());
          ???????????????System.out.println("decl?class?=?"?+?m.getDeclaringClass());
          ???????????????Class?pvec[]?=?m.getParameterTypes();
          ???????????????for?(int?j?=?0;?j?<?pvec.length;?j++)
          ???????????????????System.out.println("param?#"?+?j?+?"?"?+?pvec[j]);
          ???????????????Class?evec[]?=?m.getExceptionTypes();
          ???????????????for?(int?j?=?0;?j?<?evec.length;?j++)
          ???????????????????System.out.println("exc?#"?+?j?+?"?"?+?evec[j]);
          ???????????????System.out.println("return?type?=?"?+?m.getReturnType());
          ???????????????System.out.println("-----");
          ???????????}
          ???????}?catch?(Throwable?e)?{
          ???????????System.err.println(e);
          ???????}
          ???}
          }

          這個(gè)程序首先取得?method1?類(lèi)的描述,然后調(diào)用?getDeclaredMethods?來(lái)獲取一系列的?Method?對(duì)象,它們分別描述了定義在類(lèi)中的每一個(gè)方法,包括?public?方法、protected?方法、package?方法和?private?方法等。如果你在程序中使用?getMethods?來(lái)代替?getDeclaredMethods,你還能獲得繼承來(lái)的各個(gè)方法的信息。

          取得了?Method?對(duì)象列表之后,要顯示這些方法的參數(shù)類(lèi)型、異常類(lèi)型和返回值類(lèi)型等就不難了。這些類(lèi)型是基本類(lèi)型還是類(lèi)類(lèi)型,都可以由描述類(lèi)的對(duì)象按順序給出。

          輸出的結(jié)果如下:

          name?=?f1

          decl?class?=?class?method1

          param?#0?class?java.lang.Object

          param?#1?int

          exc?#0?class?java.lang.NullPointerException

          return?type?=?int

          -----

          name?=?main

          decl?class?=?class?method1

          param?#0?class?[Ljava.lang.String;

          return?type?=?void

          -----


          4.獲取構(gòu)造器信息

          獲取類(lèi)構(gòu)造器的用法與上述獲取方法的用法類(lèi)似,如:

          import?java.lang.reflect.*;

          public?class?constructor1?{
          ???public?constructor1()?{
          ???}

          ???protected?constructor1(int?i,?double?d)?{
          ???}

          ???public?static?void?main(String?args[])?{
          ???????try?{
          ???????????Class?cls?=?Class.forName("constructor1");
          ???????????Constructor?ctorlist[]?=?cls.getDeclaredConstructors();
          ???????????for?(int?i?=?0;?i?<?ctorlist.length;?i++)?{
          ???????????????Constructor?ct?=?ctorlist[i];
          ???????????????System.out.println("name?=?"?+?ct.getName());
          ???????????????System.out.println("decl?class?=?"?+?ct.getDeclaringClass());
          ???????????????Class?pvec[]?=?ct.getParameterTypes();
          ???????????????for?(int?j?=?0;?j?<?pvec.length;?j++)
          ???????????????????System.out.println("param?#"?+?j?+?"?"?+?pvec[j]);
          ???????????????Class?evec[]?=?ct.getExceptionTypes();
          ???????????????for?(int?j?=?0;?j?<?evec.length;?j++)
          ???????????????????System.out.println("exc?#"?+?j?+?"?"?+?evec[j]);
          ???????????????System.out.println("-----");
          ???????????}
          ???????}?catch?(Throwable?e)?{
          ???????????System.err.println(e);
          ???????}
          ???}
          }

          這個(gè)例子中沒(méi)能獲得返回類(lèi)型的相關(guān)信息,那是因?yàn)闃?gòu)造器沒(méi)有返回類(lèi)型。

          這個(gè)程序運(yùn)行的結(jié)果是:

          name?=?constructor1

          decl?class?=?class?constructor1

          -----

          name?=?constructor1

          decl?class?=?class?constructor1

          param?#0?int

          param?#1?double

          -----

          5.獲取類(lèi)的字段(域)

          找出一個(gè)類(lèi)中定義了哪些數(shù)據(jù)字段也是可能的,下面的代碼就在干這個(gè)事情:


          import?java.lang.reflect.*;

          public?class?field1?{
          ???private?double?d;
          ???public?static?final?int?i?=?37;
          ???String?s?=?"testing";

          ???public?static?void?main(String?args[])?{
          ???????try?{
          ???????????Class?cls?=?Class.forName("field1");
          ???????????Field?fieldlist[]?=?cls.getDeclaredFields();
          ???????????for?(int?i?=?0;?i?<?fieldlist.length;?i++)?{
          ???????????????Field?fld?=?fieldlist[i];
          ???????????????System.out.println("name?=?"?+?fld.getName());
          ???????????????System.out.println("decl?class?=?"?+?fld.getDeclaringClass());
          ???????????????System.out.println("type?=?"?+?fld.getType());
          ???????????????int?mod?=?fld.getModifiers();
          ???????????????System.out.println("modifiers?=?"?+?Modifier.toString(mod));
          ???????????????System.out.println("-----");
          ???????????}
          ???????}?catch?(Throwable?e)?{
          ???????????System.err.println(e);
          ???????}
          ???}
          }

          這個(gè)例子和前面那個(gè)例子非常相似。例中使用了一個(gè)新東西?Modifier,它也是一個(gè)?reflection?類(lèi),用來(lái)描述字段成員的修飾語(yǔ),如“private?int”。這些修飾語(yǔ)自身由整數(shù)描述,而且使用?Modifier.toString?來(lái)返回以“官方”順序排列的字符串描述?(如“static”在“final”之前)。這個(gè)程序的輸出是:

          name?=?d

          decl?class?=?class?field1

          type?=?double

          modifiers?=?private

          -----

          name?=?i

          decl?class?=?class?field1

          type?=?int

          modifiers?=?public?static?final

          -----

          name?=?s

          decl?class?=?class?field1

          type?=?class?java.lang.String

          modifiers?=

          -----

          和獲取方法的情況一下,獲取字段的時(shí)候也可以只取得在當(dāng)前類(lèi)中申明了的字段信息?(getDeclaredFields),或者也可以取得父類(lèi)中定義的字段?(getFields)?。


          6.根據(jù)方法的名稱(chēng)來(lái)執(zhí)行方法

          文本到這里,所舉的例子無(wú)一例外都與如何獲取類(lèi)的信息有關(guān)。我們也可以用?reflection?來(lái)做一些其它的事情,比如執(zhí)行一個(gè)指定了名稱(chēng)的方法。下面的示例演示了這一操作:

          import?java.lang.reflect.*;
          public?class?method2?{
          ???public?int?add(int?a,?int?b)?{
          ???????return?a?+?b;
          ???}
          ???public?static?void?main(String?args[])?{
          ???????try?{
          ???????????Class?cls?=?Class.forName("method2");
          ???????????Class?partypes[]?=?new?Class[2];
          ???????????partypes[0]?=?Integer.TYPE;
          ???????????partypes[1]?=?Integer.TYPE;
          ???????????Method?meth?=?cls.getMethod("add",?partypes);
          ???????????method2?methobj?=?new?method2();
          ???????????Object?arglist[]?=?new?Object[2];
          ???????????arglist[0]?=?new?Integer(37);
          ???????????arglist[1]?=?new?Integer(47);
          ???????????Object?retobj?=?meth.invoke(methobj,?arglist);
          ???????????Integer?retval?=?(Integer)?retobj;
          ???????????System.out.println(retval.intvalue());
          ???????}?catch?(Throwable?e)?{
          ???????????System.err.println(e);
          ???????}
          ???}
          }

          假如一個(gè)程序在執(zhí)行的某處的時(shí)候才知道需要執(zhí)行某個(gè)方法,這個(gè)方法的名稱(chēng)是在程序的運(yùn)行過(guò)程中指定的?(例如,JavaBean?開(kāi)發(fā)環(huán)境中就會(huì)做這樣的事),那么上面的程序演示了如何做到。

          上例中,getMethod?用于查找一個(gè)具有兩個(gè)整型參數(shù)且名為?add?的方法。找到該方法并創(chuàng)建了相應(yīng)的?Method?對(duì)象之后,在正確的對(duì)象實(shí)例中執(zhí)行它。執(zhí)行該方法的時(shí)候,需要提供一個(gè)參數(shù)列表,這在上例中是分別包裝了整數(shù)?37?和?47?的兩個(gè)?Integer?對(duì)象。執(zhí)行方法的返回的同樣是一個(gè)?Integer?對(duì)象,它封裝了返回值?84。

          7.創(chuàng)建新的對(duì)象

          對(duì)于構(gòu)造器,則不能像執(zhí)行方法那樣進(jìn)行,因?yàn)閳?zhí)行一個(gè)構(gòu)造器就意味著創(chuàng)建了一個(gè)新的對(duì)象?(準(zhǔn)確的說(shuō),創(chuàng)建一個(gè)對(duì)象的過(guò)程包括分配內(nèi)存和構(gòu)造對(duì)象)。所以,與上例最相似的例子如下:

          import?java.lang.reflect.*;

          public?class?constructor2?{
          ???public?constructor2()?{
          ???}

          ???public?constructor2(int?a,?int?b)?{
          ???????System.out.println("a?=?"?+?a?+?"?b?=?"?+?b);
          ???}

          ???public?static?void?main(String?args[])?{
          ???????try?{
          ???????????Class?cls?=?Class.forName("constructor2");
          ???????????Class?partypes[]?=?new?Class[2];
          ???????????partypes[0]?=?Integer.TYPE;
          ???????????partypes[1]?=?Integer.TYPE;
          ???????????Constructor?ct?=?cls.getConstructor(partypes);
          ???????????Object?arglist[]?=?new?Object[2];
          ???????????arglist[0]?=?new?Integer(37);
          ???????????arglist[1]?=?new?Integer(47);
          ???????????Object?retobj?=?ct.newInstance(arglist);
          ???????}?catch?(Throwable?e)?{
          ???????????System.err.println(e);
          ???????}
          ???}
          }

          根據(jù)指定的參數(shù)類(lèi)型找到相應(yīng)的構(gòu)造函數(shù)并執(zhí)行它,以創(chuàng)建一個(gè)新的對(duì)象實(shí)例。使用這種方法可以在程序運(yùn)行時(shí)動(dòng)態(tài)地創(chuàng)建對(duì)象,而不是在編譯的時(shí)候創(chuàng)建對(duì)象,這一點(diǎn)非常有價(jià)值。

          8.改變字段(域)的值

          reflection?的還有一個(gè)用處就是改變對(duì)象數(shù)據(jù)字段的值。reflection?可以從正在運(yùn)行的程序中根據(jù)名稱(chēng)找到對(duì)象的字段并改變它,下面的例子可以說(shuō)明這一點(diǎn):

          import?java.lang.reflect.*;

          public?class?field2?{
          ???public?double?d;

          ???public?static?void?main(String?args[])?{
          ???????try?{
          ???????????Class?cls?=?Class.forName("field2");
          ???????????Field?fld?=?cls.getField("d");
          ???????????field2?f2obj?=?new?field2();
          ???????????System.out.println("d?=?"?+?f2obj.d);
          ???????????fld.setDouble(f2obj,?12.34);
          ???????????System.out.println("d?=?"?+?f2obj.d);
          ???????}?catch?(Throwable?e)?{
          ???????????System.err.println(e);
          ???????}
          ???}
          }

          這個(gè)例子中,字段?d?的值被變?yōu)榱?12.34。

          9.使用數(shù)組

          本文介紹的?reflection?的最后一種用法是創(chuàng)建的操作數(shù)組。數(shù)組在?Java?語(yǔ)言中是一種特殊的類(lèi)類(lèi)型,一個(gè)數(shù)組的引用可以賦給?Object?引用。觀察下面的例子看看數(shù)組是怎么工作的:

          import?java.lang.reflect.*;

          public?class?array1?{
          ???public?static?void?main(String?args[])?{
          ???????try?{
          ???????????Class?cls?=?Class.forName("java.lang.String");
          ???????????Object?arr?=?Array.newInstance(cls,?10);
          ???????????Array.set(arr,?5,?"this?is?a?test");
          ???????????String?s?=?(String)?Array.get(arr,?5);
          ???????????System.out.println(s);
          ???????}?catch?(Throwable?e)?{
          ???????????System.err.println(e);
          ???????}
          ???}
          }

          例中創(chuàng)建了?10?個(gè)單位長(zhǎng)度的?String?數(shù)組,為第?5?個(gè)位置的字符串賦了值,最后將這個(gè)字符串從數(shù)組中取得并打印了出來(lái)。

          下面這段代碼提供了一個(gè)更復(fù)雜的例子:

          import?java.lang.reflect.*;

          public?class?array2?{
          ???public?static?void?main(String?args[])?{
          ???????int?dims[]?=?new?int[]{5,?10,?15};
          ???????Object?arr?=?Array.newInstance(Integer.TYPE,?dims);
          ???????Object?arrobj?=?Array.get(arr,?3);
          ???????Class?cls?=?arrobj.getClass().getComponentType();
          ???????System.out.println(cls);
          ???????arrobj?=?Array.get(arrobj,?5);
          ???????Array.setInt(arrobj,?10,?37);
          ???????int?arrcast[][][]?=?(int[][][])?arr;
          ???????System.out.println(arrcast[3][5][10]);
          ???}
          }
          例中創(chuàng)建了一個(gè)?5?x?10?x?15?的整型數(shù)組,并為處于?[3][5][10]?的元素賦了值為?37。注意,多維數(shù)組實(shí)際上就是數(shù)組的數(shù)組,例如,第一個(gè)?Array.get?之后,arrobj?是一個(gè)?10?x?15?的數(shù)組。進(jìn)而取得其中的一個(gè)元素,即長(zhǎng)度為?15?的數(shù)組,并使用?Array.setInt?為它的第?10?個(gè)元素賦值。

          注意創(chuàng)建數(shù)組時(shí)的類(lèi)型是動(dòng)態(tài)的,在編譯時(shí)并不知道其類(lèi)型。

          posted on 2007-09-25 00:06 -274°C 閱讀(25180) 評(píng)論(2)  編輯  收藏 所屬分類(lèi): JAVA


          FeedBack:
          # re: 轉(zhuǎn)載 Java Reflection (JAVA反射)
          2007-09-27 19:24 | 千里冰封
          反射是很強(qiáng)大的,只要我們好好去用它  回復(fù)  更多評(píng)論
            
          # re: 轉(zhuǎn)載 Java Reflection (JAVA反射) [未登錄](méi)
          2007-09-28 11:04 | -274°C
          @千里冰封

          哎,我項(xiàng)目中也沒(méi)有用到這些技術(shù)。所以只停留在初步了解的層次。該文的學(xué)習(xí)我一般是一邊看一邊敲練習(xí)代碼。有誰(shuí)需要實(shí)例代碼 以及 《侯捷觀點(diǎn) java反射機(jī)制》PDF 文件 的朋友嗎?  回復(fù)  更多評(píng)論
            

          常用鏈接

          留言簿(21)

          隨筆分類(lèi)(265)

          隨筆檔案(242)

          相冊(cè)

          JAVA網(wǎng)站

          關(guān)注的Blog

          搜索

          •  

          積分與排名

          • 積分 - 914066
          • 排名 - 40

          最新評(píng)論

          主站蜘蛛池模板: 临夏市| 凤庆县| 定兴县| 察隅县| 三原县| 宁德市| 中卫市| 镇平县| 镇远县| 安义县| 东源县| 安国市| 永和县| 建瓯市| 邛崃市| 凤翔县| 平定县| 曲沃县| 海宁市| 金堂县| 陆川县| 永善县| 晋州市| 贺兰县| 健康| 兴文县| 耒阳市| 岱山县| 墨玉县| 白水县| 合肥市| 裕民县| 辉县市| 邢台市| 封开县| 阿鲁科尔沁旗| 财经| 连州市| 迁西县| 舒城县| 玉溪市|