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

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

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

    飛翔的起點

    從這里出發

    導航

    <2009年1月>
    28293031123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    統計

    常用鏈接

    留言簿(5)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    java中的反射機制

    Reflection 是 Java 程序開發語言的特征之一,它允許運行中的 Java 程序對自身進行檢查,或者說“自審”,并能直接操作程序的內部屬性。例如,使用它能獲得 Java 類中各成員的名稱并顯示出來。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 是用來描述某個類中單個方法的一個類。還有就是getDeclaredMethod(para1,para2)來獲取這個類中的具體某一個方法,其中para1是一個String類型,具體代表的是方法名,para2是個一個Class類型的數組,其中定義個方法的具體參數類型。
        例如:
    1. Class cls = Class.forName("chb.test.reflect.Student");   
    2. Method m = cls.getDeclaredMethod("方法名",new Class[]{int.class,String.class});   
    3. m.invoke(cls.newInstance(),20,"chb");
        總結:
                //使用反射類調用某個類中的方法
                   Class c = Class.forName("com.inspur.reflect.MethodTest");
                   Method n = c.getDeclaredMethod("show", new Class[]{String.class,int.class});
                   n.invoke(c.newInstance(), "guoxzh",20);
       a.使用Class.forName("類名")來獲取類
       b.其次使用getDeclaredMethods()方法獲取該類所有的方法,也可以使用getDeclaredMethod("方法名",new Class[]{int.class,String.class})方法類獲取具體的某一個方法
       c.接著可以使用invoke(c.newInstance,param....)來調用具體的方法。


        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));   //判斷Integer(37)該對象是否是A類的對象
                    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 用法。下面的代碼就實現了這一用法:

    package com.inspur.reflect;

    import java.lang.reflect.Method;


    public class Methodtest1 {
     
     
     private int abc(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("com.inspur.reflect.Methodtest1");
       Method methodlist[]= cls.getDeclaredMethods();
       for(int i = 0;i<methodlist.length;i++){
        Method m = methodlist[i];
        System.out.println("name=="+m.getName());//得到方法的名稱
        System.out.println("decl class=="+m.getDeclaringClass());//得到定義的類名
        Class prev[] = m.getParameterTypes();   //取m方法中的所有參數
        //遍歷所有的參數
        for(int j = 0; j<prev.length;j++){
         System.out.println("param["+j+"]=="+prev[j]);
        }
        Class exec[] = m.getExceptionTypes(); //得到所有的異常
        //遍歷所有的異常
        for(int k=0;k<exec.length;k++){
         System.out.println("execption["+k+"]=="+exec[k]);
        }
       
        Class ret = m.getReturnType(); //得到每個方法的返回值
        System.out.println("return leixing=="+ret.toString()); 
       }
      }catch(Throwable e){
       System.err.println(e.getMessage());
      }
     }

    }

        這個程序首先取得 method1 類的描述,然后調用 getDeclaredMethods 來獲取一系列的 Method 對象,它們分別描述了定義在類中的每一個方法,包括 public 方法、protected 方法、package 方法和 private 方法等。如果你在程序中使用 getMethods 來代替 getDeclaredMethods,你還能獲得繼承來的各個方法的信息。同時你也可以使用Modifier.toString(m.getModifiers())來獲取方法的限制屬性。
        取得了 Method 對象列表之后,要顯示這些方法的參數類型、異常類型和返回值類型等就不難了。這些類型是基本類型還是類類型,都可以由描述類的對象按順序給出。
        輸出的結果如下:
       name==main
    decl class==class com.inspur.reflect.Methodtest1
    param[0]==class [Ljava.lang.String;
    return leixing==void
    name==abc
    decl class==class com.inspur.reflect.Methodtest1
    param[0]==class java.lang.Object
    param[1]==int
    execption[0]==class java.lang.NullPointerException
    return leixing==int    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);
                }
            }
        }
        根據指定的參數類型找到相應的構造函數并執行它,以創建一個新的對象實例。使用這種方法可以在程序運行時動態地創建對象,而不是在編譯的時候創建對象,這一點非常有價值。
        (這里如果使用無參構造器創建對象的話,這可以直接使用Class.forName("...").newInstance();來創建對象)
        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 2009-01-11 17:27 forgood 閱讀(244) 評論(0)  編輯  收藏 所屬分類: java

    主站蜘蛛池模板: 亚洲成人福利网站| 亚洲精品国产成人| 美女黄频视频大全免费的| 国产乱子精品免费视观看片| 亚洲免费福利视频| 97无码免费人妻超级碰碰碰碰| 国产亚洲sss在线播放| 毛片免费vip会员在线看| 亚洲色在线无码国产精品不卡| 在线观着免费观看国产黄| 久久亚洲精品成人无码| 四虎永久在线精品免费影视| 日亚毛片免费乱码不卡一区 | 亚洲bt加勒比一区二区| 99精品视频在线观看免费专区| 亚洲精品在线免费看| 成人免费视频软件网站| 免费精品视频在线| 亚洲精品成人无码中文毛片不卡| 国产精品免费高清在线观看| 亚洲图片中文字幕| 国产成人青青热久免费精品 | 国产大片免费网站不卡美女 | 曰批全过程免费视频在线观看无码| 亚洲成人精品久久| 成人爽A毛片免费看| 国产亚洲福利精品一区二区| 国产V亚洲V天堂无码| 99久久久国产精品免费无卡顿| 亚洲爆乳无码精品AAA片蜜桃| 久久亚洲av无码精品浪潮| 久草福利资源网站免费| 亚洲熟妇无码八V在线播放| 亚洲精品99久久久久中文字幕| 无码日韩精品一区二区免费暖暖| 亚洲成a人片在线观看播放| 国产免费人成在线视频| 午夜老司机永久免费看片| 亚洲AV无码一区二区三区久久精品| 国产亚洲精品国看不卡| 波多野结衣在线免费观看|