官术网_书友最值得收藏!

2.3 反射機制

2.3.1 動態語言的概念

動態語言指程序在運行時可以改變其結構的語言,比如新的屬性或方法的添加、刪除等結構上的變化。JavaScript、Ruby、Python等都屬于動態語言;C、C++不屬于動態語言。從反射的角度來說,Java屬于半動態語言。

2.3.2 反射機制的概念

反射機制指在程序運行過程中,對任意一個類都能獲取其所有屬性和方法,并且對任意一個對象都能調用其任意一個方法。這種動態獲取類和對象的信息,以及動態調用對象的方法的功能被稱為Java語言的反射機制。

2.3.3 反射的應用

Java中的對象有兩種類型:編譯時類型和運行時類型。編譯時類型指在聲明對象時所采用的類型,運行時類型指為對象賦值時所采用的類型。

在如下代碼中,persion對象的編譯時類型為Person,運行時類型為Student,因此無法在編譯時獲取在Student類中定義的方法:

Person persion = new Student();

因此,程序在編譯期間無法預知該對象和類的真實信息,只能通過運行時信息來發現該對象和類的真實信息,而其真實信息(對象的屬性和方法)通常通過反射機制來獲取,這便是Java語言中反射機制的核心功能。

2.3.4 Java的反射API

Java的反射API主要用于在運行過程中動態生成類、接口或對象等信息,其常用API如下。

◎ Class類:用于獲取類的屬性、方法等信息。

◎ Field類:表示類的成員變量,用于獲取和設置類中的屬性值。

◎ Method類:表示類的方法,用于獲取方法的描述信息或者執行某個方法。

◎ Constructor類:表示類的構造方法。

2.3.5 反射的步驟

反射的步驟如下。

(1)獲取想要操作的類的Class對象,該Class對象是反射的核心,通過它可以調用類的任意方法。

(2)調用Class對象所對應的類中定義的方法,這是反射的使用階段。

(3)使用反射API來獲取并調用類的屬性和方法等信息。

獲取Class對象的3種方法如下。

(1)調用某個對象的getClass方法以獲取該類對應的Class對象:

Person  p  =  new  Person();
Class  clazz  =  p.getClass();

(2)調用某個類的class屬性以獲取該類對應的Class對象:

Class clazz = Person.class;

(3)調用Class類中的forName靜態方法以獲取該類對應的Class對象,這是最安全、性能也最好的方法:

Class clazz=Class.forName("fullClassPath"); //fullClassPath為類的包路徑及名稱

我們在獲得想要操作的類的Class對象后,可以通過Class類中的方法獲取并查看該類中的方法和屬性,具體代碼如下:

//1:獲取Person類的Class對象
Class  clazz  =  Class.forName("hello.java.reflect.Persion");
//2:獲取Person類的所有方法的信息
Method[]  method  =  clazz.getDeclaredMethods();
for(Method  m:method){
    System.out.println(m.toString());
}
 //3:獲取Person類的所有成員的屬性信息
Field[]  field  =  clazz.getDeclaredFields();
for(Field  f:field){
    System.out.println(f.toString());
}
//4:獲取Person類的所有構造方法的信息
Constructor[]  constructor  =  clazz.getDeclaredConstructors();
for(Constructor  c:constructor){
    System.out.println(c.toString());
}

2.3.6 創建對象的兩種方式

創建對象的兩種方式如下。

◎ 使用Class對象的newInstance方法創建該Class對象對應類的實例,這種方法要求該Class對象對應的類有默認的空構造器。

◎ 先使用Class對象獲取指定的Constructor對象,再調用Constructor對象的newInstance方法創建Class對象對應類的實例,通過這種方法可以選定構造方法創建實例。

創建對象的具體代碼如下:

//1.1:獲取Person類的Class對象
Class  clazz  =  Class.forName("hello.java.reflect.Persion");
//2.1:使用newInstane方法創建對象
Person  p  =  (Person)  clazz.newInstance();
//1.2:獲取構造方法并創建對象
Constructor  c  =  clazz.getDeclaredConstructor
                (String.class, String.class, int.class);
//2.2:根據構造方法創建對象并設置屬性
Person p1 = (Person) c.newInstance("李四", "男",20);

2.3.7 Method的invoke方法

Method提供了關于類或接口上某個方法及如何訪問該方法的信息,那么在運行的代碼中如何動態調用該方法呢?答案就通過調用Method的invoke方法。我們通過invoke方法可以實現動態調用,比如可以動態傳入參數及將方法參數化。具體過程為:獲取對象的Method,并調用Method的invoke方法,如下所述。

(1)獲取Method對象:通過調用Class對象的getMethod(String name, Class<? >... parameterTypes)返回一個Method對象,它描述了此Class對象所表示的類或接口指定的公共成員方法。name參數是String類型,用于指定所需方法的名稱。parameterTypes參數是按聲明順序標識該方法的形參類型的Class對象的一個數組,如果parameterTypes為null,則按空數組處理。

(2)調用invoke方法:指通過調用Method對象的invoke方法來動態執行函數。invoke方法的具體使用代碼如下:

//step 1:獲取Persion類(hello.java.reflect.Persion)的Class對象
Class  clz  =  Class.forName("hello.java.reflect.Persion");
//step 2:獲取Class對象中的setName方法
Method  method  =  clz.getMethod("setName", String.class);
//step 3:獲取Constructor對象
Constructor  constructor  =  clz.getConstructor();
//step 4:根據Constructor定義對象
Object  object  =  constructor.newInstance(); //
//step 5:調用method的invoke方法,這里的method表示setName方法
//因此,相當于動態調用object對象的setName方法并傳入alex參數
method.invoke(object,  "alex");

以上代碼首先通過Class.forName方法獲取Persion類的Class對象;然后調用Persion類的Class對象的getMethod("setName", String.class)獲取一個method對象;接著使用Class對象獲取指定的Constructor對象并調用Constructor對象的newInstance方法創建Class對象對應類的實例;最后通過調用method.invoke方法實現動態調用,這樣就通過反射動態生成類的對象并調用其方法。

主站蜘蛛池模板: 博爱县| 扎兰屯市| 金塔县| 涞源县| 肇庆市| 泸水县| 水富县| 沙湾县| 缙云县| 伊春市| 左权县| 银川市| 苍山县| 宁晋县| 涪陵区| 玉田县| 肥乡县| 乌拉特中旗| 广汉市| 舟曲县| 台中县| 清水河县| 阆中市| 马龙县| 台南县| 来宾市| 涡阳县| 九江市| 疏勒县| 双桥区| 句容市| 怀集县| 贵溪市| 都安| 祁门县| 荥经县| 邵东县| 巩留县| 孝感市| 织金县| 木兰县|