<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

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

    Reflection?是?Java?程序開發語言的特征之一,它允許運行中的?Java?程序對自身進行檢查,或者說“自審”,并能直接操作程序的內部屬性。例如,使用它能獲得?Java?類中各成員的名稱并顯示出來。

    Java?的這一能力在實際應用中也許用得不是很多,但是在其它的程序設計語言中根本就不存在這一特性。例如,Pascal、C?或者?C++?中就沒有辦法在程序中獲得函數定義相關的信息。

    JavaBean?是?reflection?的實際應用之一,它能讓一些工具可視化的操作軟件組件。這些工具通過?reflection?動態的載入并取得?Java?組件(類)?的屬性。



    1.?一個簡單的例子

    考慮下面這個簡單的例子,讓我們看看?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);
    ???????}
    ???}
    }

    按如下語句執行:

    java?DumpMethods?java.util.Stack

    它的結果輸出為:

    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?類的各方法名以及它們的限制符和返回類型。

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

    2.開始使用?Reflection

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

    下面就是獲得一個?Class?對象的方法之一:

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

    這條語句得到一個?String?類的類對象。還有另一種方法,如下面的語句:

    Class?c?=?int.class;

    或者

    Class?c?=?Integer.TYPE;

    它們可獲得基本類型的類信息。其中后一種方法中訪問的是基本類型的封裝類?(如?Integer)?中預先定義好的?TYPE?字段。

    第二步是調用諸如?getDeclaredMethods?的方法,以取得該類中定義的所有方法的列表。

    一旦取得這個信息,就可以進行第三步了??使用?reflection?API?來操作這些信息,如下面這段代碼:

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

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

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

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

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

    模擬?instanceof?操作符

    得到類信息之后,通常下一個步驟就是解決關于?Class?對象的一些基本的問題。例如,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);
    ???????}
    ???}
    }

    在這個例子中創建了一個?A?類的?Class?對象,然后檢查一些對象是否是?A?的實例。Integer(37)?不是,但?new?A()?是。

    3.找出類的方法

    找出一個類中定義了些什么方法,這是一個非常有價值也非常基礎的?reflection?用法。下面的代碼就實現了這一用法:

    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);
    ???????}
    ???}
    }

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

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

    輸出的結果如下:

    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.獲取構造器信息

    獲取類構造器的用法與上述獲取方法的用法類似,如:

    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);
    ???????}
    ???}
    }

    這個例子中沒能獲得返回類型的相關信息,那是因為構造器沒有返回類型。

    這個程序運行的結果是:

    name?=?constructor1

    decl?class?=?class?constructor1

    -----

    name?=?constructor1

    decl?class?=?class?constructor1

    param?#0?int

    param?#1?double

    -----

    5.獲取類的字段(域)

    找出一個類中定義了哪些數據字段也是可能的,下面的代碼就在干這個事情:


    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);
    ???????}
    ???}
    }

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

    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?=

    -----

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


    6.根據方法的名稱來執行方法

    文本到這里,所舉的例子無一例外都與如何獲取類的信息有關。我們也可以用?reflection?來做一些其它的事情,比如執行一個指定了名稱的方法。下面的示例演示了這一操作:

    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);
    ???????}
    ???}
    }

    假如一個程序在執行的某處的時候才知道需要執行某個方法,這個方法的名稱是在程序的運行過程中指定的?(例如,JavaBean?開發環境中就會做這樣的事),那么上面的程序演示了如何做到。

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

    7.創建新的對象

    對于構造器,則不能像執行方法那樣進行,因為執行一個構造器就意味著創建了一個新的對象?(準確的說,創建一個對象的過程包括分配內存和構造對象)。所以,與上例最相似的例子如下:

    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);
    ???????}
    ???}
    }

    根據指定的參數類型找到相應的構造函數并執行它,以創建一個新的對象實例。使用這種方法可以在程序運行時動態地創建對象,而不是在編譯的時候創建對象,這一點非常有價值。

    8.改變字段(域)的值

    reflection?的還有一個用處就是改變對象數據字段的值。reflection?可以從正在運行的程序中根據名稱找到對象的字段并改變它,下面的例子可以說明這一點:

    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);
    ???????}
    ???}
    }

    這個例子中,字段?d?的值被變為了?12.34。

    9.使用數組

    本文介紹的?reflection?的最后一種用法是創建的操作數組。數組在?Java?語言中是一種特殊的類類型,一個數組的引用可以賦給?Object?引用。觀察下面的例子看看數組是怎么工作的:

    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);
    ???????}
    ???}
    }

    例中創建了?10?個單位長度的?String?數組,為第?5?個位置的字符串賦了值,最后將這個字符串從數組中取得并打印了出來。

    下面這段代碼提供了一個更復雜的例子:

    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]);
    ???}
    }
    例中創建了一個?5?x?10?x?15?的整型數組,并為處于?[3][5][10]?的元素賦了值為?37。注意,多維數組實際上就是數組的數組,例如,第一個?Array.get?之后,arrobj?是一個?10?x?15?的數組。進而取得其中的一個元素,即長度為?15?的數組,并使用?Array.setInt?為它的第?10?個元素賦值。

    注意創建數組時的類型是動態的,在編譯時并不知道其類型。

    posted on 2007-09-25 00:06 -274°C 閱讀(25182) 評論(2)  編輯  收藏 所屬分類: JAVA


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

    哎,我項目中也沒有用到這些技術。所以只停留在初步了解的層次。該文的學習我一般是一邊看一邊敲練習代碼。有誰需要實例代碼 以及 《侯捷觀點 java反射機制》PDF 文件 的朋友嗎?  回復  更多評論
      

    常用鏈接

    留言簿(21)

    隨筆分類(265)

    隨筆檔案(242)

    相冊

    JAVA網站

    關注的Blog

    搜索

    •  

    積分與排名

    • 積分 - 914354
    • 排名 - 40

    最新評論

    主站蜘蛛池模板: 一本久久免费视频| 亚洲一卡2卡4卡5卡6卡残暴在线| 午夜在线亚洲男人午在线| 亚洲美女在线国产| 亚洲一区二区三区高清视频| 永久黄色免费网站| 亚洲国产夜色在线观看| 久久99九九国产免费看小说| 亚洲人成电影网站久久| 岛国大片免费在线观看| 亚洲国产成人久久综合| 全亚洲最新黄色特级网站| 久久国产免费直播| 亚洲AV永久无码精品水牛影视| 久久99国产综合精品免费| 亚洲精品国产精品国自产网站| 成人片黄网站A毛片免费| 久久亚洲精品无码gv| 国产亚洲成归v人片在线观看| 最新国产乱人伦偷精品免费网站 | 亚洲妓女综合网99| 国产1000部成人免费视频| 亚洲国产欧洲综合997久久| 免费在线黄色网址| 久热免费在线视频| 亚洲一区二区无码偷拍| 亚洲成片观看四虎永久| 香港a毛片免费观看| 亚洲码欧美码一区二区三区| 亚洲真人日本在线| 99re在线视频免费观看| 亚洲精品无码专区在线播放| 伊人亚洲综合青草青草久热| 最近免费2019中文字幕大全| 亚洲AV噜噜一区二区三区| 亚洲AV无码专区国产乱码电影| 思思99re66在线精品免费观看| 美女网站在线观看视频免费的| 亚洲婷婷在线视频| 中文字幕亚洲天堂| 手机在线免费视频|