java reflection part 2

5.獲取類的字段(域)

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

  1. import java.lang.reflect.*;
  2. public class field1 {
  3.    private double d;
  4.    public static final int i = 37;
  5.     String s = "testing";
  6.    public static void main(String args[]) {
  7.       try {
  8.             Class cls = Class.forName("field1");
  9.             Field fieldlist[] = cls.getDeclaredFields();
  10.            for (int i = 0; i < fieldlist.length; i++) {
  11.                Field fld = fieldlist[i];
  12.                System.out.println("name = " + fld.getName());
  13.                System.out.println("decl class = " + fld.getDeclaringClass());
  14.                System.out.println("type = " + fld.getType());
  15.               int mod = fld.getModifiers();
  16.                System.out.println("modifiers = " + Modifier.toString(mod));
  17.                System.out.println("-----");
  18.             }
  19.        } catch (Throwable e) {
  20.             System.err.println(e);
  21.        }
  22.     }
  23. }

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

  1. name = d
  2. decl class = class field1
  3. type = double
  4. modifiers = private
  5. -----
  6. name = i
  7. decl class = class field1
  8. type = int
  9. modifiers = public static final
  10. -----
  11. name = s
  12. decl class = class field1
  13. type = class java.lang.String
  14. modifiers =

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

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

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

  1. import java.lang.reflect.*;
  2. public class method2 {
  3.    public int add(int a, int b) {
  4.       return a + b;
  5.     }
  6.    public static void main(String args[]) {
  7.       try {
  8.             Class cls = Class.forName("method2");
  9.             Class partypes[] = new Class[2];
  10.             partypes[0] = Integer.TYPE;
  11.             partypes[1] = Integer.TYPE;
  12.       
  13.             Method meth = cls.getMethod("add", partypes);
  14.             method2 methobj = new method2();
  15.             Object arglist[] = new Object[2];
  16.             arglist[0] = new Integer(37);
  17.             arglist[1] = new Integer(47);
  18.             Object retobj = meth.invoke(methobj, arglist);
  19.             Integer retval = (Integer) retobj;
  20.             System.out.println(retval.intValue());
  21.        } catch (Throwable e) {
  22.             System.err.println(e);
  23.        }
  24.     }
  25. }

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

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

7.創建新的對象

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

  1. import java.lang.reflect.*;
  2. public class constructor2 {
  3.    public constructor2() {
  4.     }
  5.    public constructor2(int a, int b) {
  6.        System.out.println("a = " + a + " b = " + b);
  7.     }
  8.    public static void main(String args[]) {
  9.       try {
  10.             Class cls = Class.forName("constructor2");
  11.             Class partypes[] = new Class[2];
  12.             partypes[0] = Integer.TYPE;
  13.             partypes[1] = Integer.TYPE;
  14.             Constructor ct = cls.getConstructor(partypes);
  15.             Object arglist[] = new Object[2];
  16.             arglist[0] = new Integer(37);
  17.             arglist[1] = new Integer(47);
  18.             Object retobj = ct.newInstance(arglist);
  19.        } catch (Throwable e) {
  20.             System.err.println(e);
  21.        }
  22.     }
  23. }

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

8.改變字段(域)的值

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

  1. import java.lang.reflect.*;
  2. public class field2 {
  3.    public double d;
  4.    public static void main(String args[]) {
  5.       try {
  6.             Class cls = Class.forName("field2");
  7.             Field fld = cls.getField("d");
  8.             field2 f2obj = new field2();
  9.             System.out.println("d = " + f2obj.d);
  10.             fld.setDouble(f2obj, 12.34);
  11.             System.out.println("d = " + f2obj.d);
  12.        } catch (Throwable e) {
  13.             System.err.println(e);
  14.        }
  15.     }
  16. }

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

9.使用數組

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

  1. import java.lang.reflect.*;
  2. public class array1 {
  3.    public static void main(String args[]) {
  4.       try {
  5.             Class cls = Class.forName("java.lang.String");
  6.             Object arr = Array.newInstance(cls, 10);
  7.             Array.set(arr, 5, "this is a test");
  8.             String s = (String) Array.get(arr, 5);
  9.             System.out.println(s);
  10.        } catch (Throwable e) {
  11.             System.err.println(e);
  12.        }
  13.     }
  14. }

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

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

  1. import java.lang.reflect.*;
  2. public class array2 {
  3.    public static void main(String args[]) {
  4.       int dims[] = new int[]{5, 10, 15};
  5.        Object arr = Array.newInstance(Integer.TYPE, dims);
  6.        Object arrobj = Array.get(arr, 3);
  7.        Class cls = arrobj.getClass().getComponentType();
  8.        System.out.println(cls);
  9.        arrobj = Array.get(arrobj, 5);
  10.        Array.setInt(arrobj, 10, 37);
  11.       int arrcast[][][] = (int[][][]) arr;
  12.        System.out.println(arrcast[3][5][10]);
  13.     }
  14. }

例中創建了一個 5 x 10 x 15 的整型數組,併爲處於 [3][5][10] 的元素賦了值爲 37。注意,多維數組實際上就是數組的數組,例如,第一個 Array.get 之後,arrobj 是一個 10 x 15 的數組。進而取得其中的一個元素,即長度爲 15 的數組,並使用 Array.setInt 爲它的第 10 個元素賦值。

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

發佈了34 篇原創文章 · 獲贊 0 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章