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

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

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

    隨筆 - 10  文章 - 16  trackbacks - 0
    <2025年5月>
    27282930123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    常用鏈接

    留言簿(1)

    隨筆分類

    文章分類

    我的好友

    搜索

    •  

    最新隨筆

    最新評論

    閱讀排行榜

    評論排行榜

    作者:yonnie?文章來源:http://yonnie.blog.hexun.com/

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

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

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

    1、一個簡單的例子
    考慮下面這個簡單的例子,讓我們看看 reflection 是如何工作的。

    ?1 import ?java.lang.reflect. * ;
    ?2

    ?3 public ? class ?DumpMethods?
    {
    ?4 ???? public ? static ? void ?main(String?args[])?
    {
    ?5 ???????? try ?
    {
    ?6 ????????????Class?c? = ?Class.forName(args[ 0
    ]);
    ?7 ????????????Method?m[]? =
    ?c.getDeclaredMethods();
    ?8 ???????????? for ?( int ?i? = ? 0 ;?i? < ?m.length;?i ++
    )
    ?9
    ????????????????System.out.println(m[i].toString());
    10 ????????}
    ? catch ?(Throwable?e)? {
    11
    ????????????System.err.println(e);
    12 ????????}

    13 ????}

    14 }

    15

    按如下語句執行:
    java?DumpMethods?java.util.Stack

    它的結果輸出為:
    public ? synchronized ?java.lang.Object?java.util.Stack.pop()
    public
    ?java.lang.Object?java.util.Stack.push(java.lang.Object)
    public ? boolean
    ?java.util.Stack.empty()
    public ? synchronized
    ?java.lang.Object?java.util.Stack.peek()
    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 2006-10-30 12:48 Toez 閱讀(198) 評論(0)  編輯  收藏 所屬分類: Java

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


    網站導航:
     
    主站蜘蛛池模板: 亚洲爆乳精品无码一区二区| 四虎免费影院ww4164h| 国产亚洲sss在线播放| 亚洲午夜无码久久久久| 日韩免费一区二区三区| 98精品全国免费观看视频| 深夜福利在线免费观看| 亚洲无人区视频大全| 亚洲第一AV网站| 亚洲国产精品一区二区九九| 毛片免费在线观看网址| 99免费观看视频| 国产成年无码久久久免费| 思思久久99热免费精品6| wwwxxx亚洲| 亚洲成AV人片久久| 久久综合日韩亚洲精品色| 久久久久亚洲?V成人无码| 国产男女猛烈无遮挡免费视频网站| 亚欧色视频在线观看免费| 国产精品区免费视频| 久久久久免费视频| 一级毛片a免费播放王色电影 | 亚洲人成77777在线播放网站不卡 亚洲人成77777在线观看网 | 久久久久国产免费| 99在线免费观看| 国产精品成人69XXX免费视频| 国产成人高清亚洲一区久久| 亚洲另类无码一区二区三区| 亚洲中文精品久久久久久不卡| 亚洲综合激情九月婷婷| 久久精品国产亚洲AV高清热| 国产V亚洲V天堂无码| 亚洲AV无码一区二区乱孑伦AS| 国产亚洲精品国产| 国产av天堂亚洲国产av天堂| 亚洲国产精品VA在线观看麻豆 | 亚洲日本在线电影| 亚洲综合久久精品无码色欲| 亚洲三级视频在线| 亚洲AV无码乱码麻豆精品国产|