国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

細(xì)說JAVA反射

2019-11-14 15:15:19
字體:
供稿:網(wǎng)友

 

Reflection 是 java 程序開發(fā)語言的特征之一,它允許運(yùn)行中的 Java 程序?qū)ψ陨磉M(jìn)行檢查,或者說“自審”,并能直接操作程序的內(nèi)部屬性。例如,使用它能獲得 Java 類中各成員的名稱并顯示出來。JavaBean 是 reflection 的實(shí)際應(yīng)用之一,它能讓一些工具可視化的操作軟件組件。這些工具通過 reflection 動態(tài)的載入并取得 Java 組件(類) 的屬性。
    1. 一個(gè)簡單的例子
    考慮下面這個(gè)簡單的例子,讓我們看看 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);            }        }    }

     按如下語句執(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 類的各方法名以及它們的限制符和返回類型。

    這個(gè)程序使用 Class.forName 載入指定的類,然后調(diào)用 getDeclaredMethods 來獲取這個(gè)類中定義了的方法列表。java.lang.reflect.Methods是用來描述某個(gè)類中單個(gè)方法的一個(gè)類。
 
2.開始使用 Reflection
    用于 reflection 的類,如 Method,可以在 java.lang.relfect 包中找到。使用這些類的時(shí)候必須要遵循三個(gè)步驟:
    第一步是獲得你想操作的類的 java.lang.Class 對象
    在運(yùn)行中的 Java 程序中,用 java.lang.Class 類來描述類和接口等。
    下面就是獲得一個(gè) Class 對象的方法之一:       
Class c = Class.forName("java.lang.String");

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

Class c = int.class;
    或者
  
Class c = Integer.TYPE;
    它們可獲得基本類型的類信息。其中后一種方法中訪問的是基本類型的封裝類 (如 Integer) 中預(yù)先定義好的 TYPE 字段。
    第二步是調(diào)用諸如 getDeclaredMethods 的方法,以取得該類中定義的所有方法的列表
    一旦取得這個(gè)信息,就可以進(jìn)行第三步了——
    使用 reflection API 來操作這些信息,如下面這段代碼:
Class c = Class.forName("java.lang.String");Method m[] = c.getDeclaredMethods();System.out.println(m[0].toString());

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

    在下面的例子中,這三個(gè)步驟將為使用 reflection 處理特殊應(yīng)用程序提供例證。
    模擬 instanceof 操作符
    得到類信息之后,通常下一個(gè)步驟就是解決關(guān)于 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);            }        }    }

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

 3.找出類的方法
    找出一個(gè)類中定義了些什么方法,這是一個(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 類的描述,然后調(diào)用 getDeclaredMethods 來獲取一系列的 Method 對象,它們分別描述了定義在類中的每一個(gè)方法,包括 public 方法、protected 方法、package 方法和 private 方法等。如果你在程序中使用 getMethods 來代替 getDeclaredMethods,你還能獲得繼承來的各個(gè)方法的信息。
    取得了 Method 對象列表之后,要顯示這些方法的參數(shù)類型、異常類型和返回值類型等就不難了。這些類型是基本類型還是類類型,都可以由描述類的對象按順序給出。
    輸出的結(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)造器信息
    獲取類構(gòu)造器的用法與上述獲取方法的用法類似,如:

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è)例子中沒能獲得返回類型的相關(guān)信息,那是因?yàn)闃?gòu)造器沒有返回類型

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

 
   name = constructor1    decl class = class constructor1    -----    name = constructor1    decl class = class constructor1    param #0 int    param #1 double    -----

 

    5.獲取類的字段(域)
    找出一個(gè)類中定義了哪些數(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 類,用來描述字段成員的修飾語,如“private int”。這些修飾語自身由整數(shù)描述,而且使用 Modifier.toString 來返回以“官方”順序排列的字符串描述 (如“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)前類中申明了的字段信息 (getDeclaredFields),或者也可以取得父類中定義的字段 (getFields) 。

 

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

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è)方法的名稱是在程序的運(yùn)行過程中指定的 (例如,JavaBean 開發(fā)環(huán)境中就會做這樣的事),那么上面的程序演示了如何做到。
    上例中,getMethod 用于查找一個(gè)具有兩個(gè)整型參數(shù)且名為 add 的方法。找到該方法并創(chuàng)建了相應(yīng)的 Method 對象之后,在正確的對象實(shí)例中執(zhí)行它。執(zhí)行該方法的時(shí)候,需要提供一個(gè)參數(shù)列表,這在上例中是分別包裝了整數(shù) 37 和 47 的兩個(gè) Integer 對象。執(zhí)行方法的返回的同樣是一個(gè) Integer 對象,它封裝了返回值 84。
    7.創(chuàng)建新的對象
    對于構(gòu)造器,則不能像執(zhí)行方法那樣進(jìn)行,因?yàn)閳?zhí)行一個(gè)構(gòu)造器就意味著創(chuàng)建了一個(gè)新的對象 (準(zhǔn)確的說,創(chuàng)建一個(gè)對象的過程包括分配內(nèi)存和構(gòu)造對象)。所以,與上例最相似的例子如下:

    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ù)類型找到相應(yīng)的構(gòu)造函數(shù)并執(zhí)行它,以創(chuàng)建一個(gè)新的對象實(shí)例。使用這種方法可以在程序運(yùn)行時(shí)動態(tài)地創(chuàng)建對象,而不是在編譯的時(shí)候創(chuàng)建對象,這一點(diǎn)非常有價(jià)值。
    (這里如果使用無參構(gòu)造器創(chuàng)建對象的話,這可以直接使用Class.forName("...").newInstance();來創(chuàng)建對象
    8.改變字段(域)的值
    reflection 的還有一個(gè)用處就是改變對象數(shù)據(jù)字段的值。reflection 可以從正在運(yùn)行的程序中根據(jù)名稱找到對象的字段并改變它,下面的例子可以說明這一點(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 語言中是一種特殊的類類型,一個(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è)單位長度的 String 數(shù)組,為第 5 個(gè)位置的字符串賦了值,最后將這個(gè)字符串從數(shù)組中取得并打印了出來。
    下面這段代碼提供了一個(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è)元素,即長度為 15 的數(shù)組,并使用 Array.setInt 為它的第 10 個(gè)元素賦值。
    注意創(chuàng)建數(shù)組時(shí)的類型是動態(tài)的,在編譯時(shí)并不知道其類型。

 

   來源:http://itlab.idcquan.com/Java/base/742955_4.html


發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 罗山县| 安西县| 新绛县| 宿州市| 武冈市| 嘉鱼县| 民权县| 奉贤区| 屯留县| 德化县| 陇西县| 邓州市| 南木林县| 城固县| 浏阳市| 徐州市| 汽车| 禹城市| 鄢陵县| 嵊州市| 民乐县| 新乡市| 象山县| 得荣县| 瓦房店市| 阳春市| 吴堡县| 通化县| 定南县| 宝山区| 玉环县| 池州市| 松原市| 基隆市| 柏乡县| 昌宁县| 余江县| 平南县| 关岭| 襄垣县| 中超|