欲生成對象實(shí)體,在Reflection 動(dòng)態(tài)機制中有兩種作法,一個(gè)針對“無(wú)自變量ctor”,一個(gè)針對“帶參數ctor”。如果欲調用的是“帶參數ctor“就比較麻煩些,不再調用Class的newInstance(),而是調用Constructor 的newInstance()。首先準備一個(gè)Class[]做為ctor的參數類(lèi)型,然后以此為自變量調用getConstructor(),獲得一個(gè)專(zhuān)屬ctor。接下來(lái)再準備一個(gè)Object[] 做為ctor實(shí)參值,調用上述專(zhuān)屬ctor的newInstance()。
下面做個(gè)例子,該例子的反射對象沒(méi)有構造方法(實(shí)際上是默認的構造方法),無(wú)自變量,動(dòng)態(tài)生成“Class object 所對應之class”的對象實(shí)體,代碼如下:
首先建立com.lansin.ghk包,在其下建立兩個(gè)類(lèi):Person.java和Test1.java。
package com.lansin.ghk;public class Person{private String name;private String address;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}@Overridepublic String toString() {return "名稱(chēng)為" + this.getName() + ", 地址為" + this.getAddress();}}
package com.lansin.ghk;import java.lang.reflect.Field;import java.lang.reflect.Method;public class Test1 {public static void main(String[] args) throws Exception {Class<?> classType = Class.forName("com.lansin.ghk.Person");Object obj = null;obj = classType.newInstance();Field fields[] = classType.getDeclaredFields();for(int i=0; i<fields.length;i++){Field field = fields[i];String fieldName = field.getName();String firstLetter = fieldName.substring(0, 1).toUpperCase();String getMethodName = "get" + firstLetter + fieldName.substring(1);String setMethodName = "set" + firstLetter + fieldName.substring(1);Method getMethod = classType.getMethod(getMethodName);Method setMethod = classType.getMethod(setMethodName,field.getType());if("name".equals(fieldName)){setMethod.invoke(obj, "邁克·泰森");}else if("address".equals(fieldName)){setMethod.invoke(obj, "美國");}}System.out.println(obj);}}
運行結果為:“名稱(chēng)為邁克·泰森, 地址為美國”。
下面做個(gè)例子,該例子的反射對象包含構造方法,有自變量,動(dòng)態(tài)生成“Class object 所對應之class”的對象實(shí)體,代碼如下:
有構造方法的Person類(lèi)只需在上面的Person類(lèi)里加一個(gè)構造方法;Test2類(lèi)“反射”Person。
package com.lansin.ghk;public class Person{private String name;private String address;public Person(String name, String address){this.name = name;this.address = address;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}@Overridepublic String toString() {return "名稱(chēng)為" + this.getName() + ", 地址為" + this.getAddress();}}
package com.lansin.ghk;import java.lang.reflect.Constructor;public class Test2 {public static void main(String[] args) throws Exception {Class<?> c = Class.forName("com.lansin.ghk.Person");Class[] pTypes = new Class[]{String.class, String.class};Constructor ctor = c.getConstructor(pTypes);Object obj = null;Object[] arg = new Object[]{"邁克·泰森", "美國"};obj = ctor.newInstance(arg);System.out.println(obj);}}
運行,和上個(gè)程序結果一樣:“名稱(chēng)為邁克·泰森, 地址為美國”。
比較上面兩段程序:首先要提供一個(gè)對象類(lèi)的地址全稱(chēng)(包名+類(lèi)名)。
(一)對于沒(méi)有構造函數的類(lèi),在運行時(shí)刻創(chuàng )建該對象所屬類(lèi)的對象實(shí)例:
先聲明一個(gè)泛型Class,
Class<?> classType = Class.forName("com.lansin.ghk.Person");
然后由泛型對象classType生成實(shí)例,
Object obj = classType.newInstance();
接下來(lái)調用反射機制提供的各種方法進(jìn)行動(dòng)態(tài)處理;
(二)對于有構造函數的類(lèi),在運行時(shí)刻創(chuàng )建該對象所屬類(lèi)的對象實(shí)例:
同樣要先聲明一個(gè)泛型Class,
Class<?> classType = Class.forName("com.lansin.ghk.Person");
創(chuàng )建一個(gè)“類(lèi)型類(lèi)”集合,因為Person類(lèi)的構造函數有兩個(gè)string類(lèi)型的形參,
Class[] pTypes = new Class[]{String.class, String.class};
接下來(lái)由生成的“由對象在運行時(shí)所生成所屬類(lèi)的對象”來(lái)創(chuàng )建一個(gè)帶有形參(是個(gè)集合)的構造器,
Constructor ctor = classType .getConstructor(pTypes);
最后由構造器生成一個(gè)實(shí)例對象,但是首先要設定實(shí)參,
設定實(shí)參:Object[] arg = new Object[]{"邁克·泰森", "美國"};
實(shí)例化對象:Object obj = ctor.newInstance(arg);
OK了。
其實(shí)到這里我還有很多細節沒(méi)有說(shuō),這個(gè)要在以后的工作中多多學(xué)習,多多參考文檔,java api是個(gè)好東西。
下面的例子是在運行時(shí)調用Method,代碼如下:
public class InvokeTester {public int add(int param1, int param2) {return param1 + param2;}public String echo(String msg) {return "echo: " + msg;}public static void main(String[] args) throws Exception {Class<?> classType = InvokeTester.class;Object invokeTester = classType.newInstance();// 調用InvokeTester對象的add()方法Method addMethod = classType.getMethod("add", new Class[] { int.class,int.class });Object result = addMethod.invoke(invokeTester, new Object[] {new Integer(100), new Integer(200) });System.out.println((Integer) result);// 調用InvokeTester對象的echo()方法Method echoMethod = classType.getMethod("echo",new Class[] { String.class });result = echoMethod.invoke(invokeTester, new Object[] { "Hello" });System.out.println((String) result);}}
這個(gè)動(dòng)作和上述調用“帶參數之ctor”相當類(lèi)似。首先準備一個(gè)Class[]做為參數類(lèi)型(本例指定其中一個(gè)是String,另一個(gè)是Hashtable),然后以此為自變量調用getMethod(),獲得特定的Method object。接下來(lái)準備一個(gè)Object[]放置自變量,然后調用上述所得之特定Method object的invoke()。
為什么獲得Method object時(shí)不需指定回返類(lèi)型?
因為method overloading機制要求signature必須唯一,而回返類(lèi)型并非signature的一個(gè)成份。換句話(huà)說(shuō),只要指定了method名稱(chēng)和參數列,就一定指出了一個(gè)獨一無(wú)二的method。
下面的類(lèi)是運行時(shí)變更Field的內容,比較簡(jiǎn)單,代碼如下:
package com.lansin.ghk;import java.lang.reflect.Field;public class TestField {public double d;public static void main(String[] args) throws Exception {Class c = Class.forName("com.lansin.ghk.TestField");Field f = c.getField("d");TestField obj = new TestField();System.out.println("d= " + (Double)f.get(obj));f.set(obj, 12.34);System.out.println("d= " + obj.d);}}
與先前兩個(gè)動(dòng)作相比,“變更field內容”輕松多了,因為它不需要參數和自變量。首先調用Class的getField()并指定field名稱(chēng)。獲得特定的Field object之后便可直接調用Field的get()和set()。
聯(lián)系客服