一、 通過反射調用類中的方法
在正常情況下,得到類的對象后,我們就可以直接調用類中的方法了,如果要想調用的話,則肯定必須清楚地知道要調用的方法是什么,之后通過Class類中的getMethod方法,可得到Method對象。
public Method getMethod(String name,
Class<?>... parameterTypes)
throws NoSuchMethodException,
SecurityException
當獲取到Method對象后,可以通過該對象來執行方法,但是在方法調用的時候,因為會牽扯到方法中參數的問題,所以通過getMethod()取得的時候,必須設置好參數類型。
package org.chen.yuan.reflect; interface China{ // 定義China接口 public static final String NATIONAL = "China" ; // 定義全局常量 public static final String AUTHOR = "李興華" ; // 定義全局常量 public void sayChina() ; // 無參的,沒有返回值的方法 public String sayHello(String name,int age) ; // 定義有兩個參數的方法,並返回內容 } public class Person implements China{ private String name ; private int age ; public Person(){ // 無參構造 } public Person(String name){ this.name = name ; // 設置name屬性 } public Person(String name,int age){ this(name) ; this.age = age ; } public void sayChina(){ // 覆寫方法 System.out.println("作者:" + AUTHOR + ",國籍:" + NATIONAL) ; } public String sayHello(String name,int age){ return name + ",你好!我今年:" + age + "歲了!" ; } public void setName(String name){ this.name = name ; } public void setAge(int age){ this.age = age ; } public String getName(){ return this.name ; } public int getAge(){ return this.age ; } };我們調用sayChina()方法,此方法中沒有任何參數。
執行調用的方法,需通過Method的invoke方法來實現:
public Object invoke(Object obj,
Object... args)
throws IllegalAccessException,
IllegalArgumentException,
InvocationTargetException
示例1:(調用無參的方法)
package org.chen.yuan.reflect; interface China{ // 定義China接口 public static final String NATIONAL = "China" ; // 定義全局常量 public static final String AUTHOR = "沉緣" ; // 定義全局常量 public void sayChina() ; // 無參的,沒有返回值的方法 public String sayHello(String name,int age) ; // 定義有兩個參數的方法,並返回內容 } public class Person implements China{ private String name ; private int age ; public Person(){ // 無參構造 } public Person(String name){ this.name = name ; // 設置name屬性 } public Person(String name,int age){ this(name) ; this.age = age ; } public void sayChina(){ // 覆寫方法 System.out.println("作者:" + AUTHOR + ",國籍:" + NATIONAL) ; } public String sayHello(String name,int age){ return name + ",你好!我今年:" + age + "歲了!" ; } public void setName(String name){ this.name = name ; } public void setAge(int age){ this.age = age ; } public String getName(){ return this.name ; } public int getAge(){ return this.age ; } };
我們在Person.java 類中定義了一個無參方法sayChina和一個有參數的方法sayHello,接下來,我們調用無參數的方法:
package org.chen.yuan.reflect; import java.lang.reflect.Method; public class InvokeSyaChinaDemo { public static void main(String[] args) { Class<?> c1 = null; try { c1 = Class.forName("org.chen.yuan.reflect.Person"); Method met = c1.getMethod("sayChina"); met.invoke(c1.newInstance()); } catch (Exception e) { e.printStackTrace(); } } }
輸出: 作者:沉緣,國籍:China
可以看出,通過上述反射的方式,我們能夠順利的調用Person類中的方法。 那思考下,如果我們要調用含有參數的方法sayHello,該如何做呢?
可以想象,如果方法里存在了參數,則必須設置參數的類型及內容。
public class InvokeSayHelloDemo { public static void main(String[] args) throws Exception { Class<?> c1 = null; c1 = Class.forName("org.chen.yuan.reflect.Person"); Method met = c1.getMethod("sayHello", String.class, int.class); String result = (String) met.invoke(c1.newInstance(), "沉緣", 25); System.out.println(result); } }
輸出: 沉緣,你好!我今年:25歲了!
二、 通過反射調用類中的setter及getter方法
setter和getter方法是訪問類屬性的標准方法,如果一個類中的屬性被封裝,則必須通過setter及getter方法設設置和取得,實際上此方法的操作之所以要這樣規定,主要是由於反射機制可以給予支持。
通過反射可以調用setter及getter方法。
package org.chen.yuan.reflect; import java.lang.reflect.Method; public class InvokeSetGetDemo { public static void main(String[] args) throws Exception { Class<?> c1 = null; Object obj = null; c1 = Class.forName("org.chen.yuan.reflect.Person"); obj = c1.newInstance(); setter(obj, "name", "沉緣", String.class); getter(obj, "name"); setter(obj, "age", 25, int.class); getter(obj, "age"); } /** * @param obj 要操作的對象 * @param att 要操作的屬性 * @param value 要設置的屬性數據 * @param type 要設置的屬性的類型 */ public static void setter(Object obj, String att, Object value, Class<?> type) { try { Method met = obj.getClass().getMethod("set" + initStr(att), type); met.invoke(obj, value); } catch (Exception e) { e.printStackTrace(); } } /** * @param obj 要操作的對象 * @param att 要操作的屬性 */ public static void getter(Object obj, String att) throws Exception { Method met = obj.getClass().getMethod("get" + initStr(att)); System.out.println(met.invoke(obj)); } /** * 將單詞首字母大寫 * * @param old * @return */ public static String initStr(String old) { String newStr = old.substring(0, 1).toUpperCase() + old.substring(1); return newStr; } }
三、 通過反射調用屬性
如果假設要操作一個類中的屬性,則也可以通過Field完成,而不必麻煩的通過setter和getter。Class類中,獲取類中Field的方法:
1) 得到類中公共屬性
public Field getField(String name)
throws NoSuchFieldException,
SecurityException
2)得到本類屬性
public Field getDeclaredField(String name)
throws NoSuchFieldException,
SecurityException
而在Field類中,提供了獲取屬性內容及設置屬性內容的方法:
1) 獲取屬性內容
public Object get(Object obj)
throws IllegalArgumentException,
IllegalAccessException
2) 設置屬性內容
public void set(Object obj,
Object value)
throws IllegalArgumentException,
IllegalAccessException
還有一點需要注意,訪問類中的私有屬性時,必須要讓該屬性對外可見:
public void setAccessible(boolean flag)
throws SecurityException
該方法繼承自Field的父類:
Class AccessibleObject
只要把該方法的參數內容設置為true即可。
public class InvokeFieldDemo { public static void main(String args[]) throws Exception { Class<?> c1 = null; Object obj = null; c1 = Class.forName("org.chen.yuan.reflect.Person"); // 實例化Class對象 obj = c1.newInstance(); Field nameField = null; Field ageField = null; nameField = c1.getDeclaredField("name"); // 取得name屬性 ageField = c1.getDeclaredField("age"); // 取得name屬性 nameField.setAccessible(true); // 此屬性對外部可見 ageField.setAccessible(true); // 此屬性對外部可見 nameField.set(obj, "沉緣"); // 設置name屬性內容 ageField.set(obj, 25); // 設置age屬性內容 System.out.println("姓名:" + nameField.get(obj)); System.out.println("年齡:" + ageField.get(obj)); } };
輸出:
姓名:沉緣
年齡:25
可見,操作屬性,未必需要setter和getter方法的支持,但是,為了保證程序的安全性,最好還是通過setter和getter方法對屬性進行操作。
四、 通過反射操作數組
反射機制不光能用在類中,也可以應用在任意的引用數據類型上,當然,這就包含了數組,數組使用Array類完成。
Class類中存在以下一個方法:
public Class<?> getComponentType()
Array類中得到數組指定下標的內容:
public static Object get(Object array,
int index)
throws IllegalArgumentException,
ArrayIndexOutOfBoundsException
Array類中修改內容:
public static void set(Object array,
int index,
Object value)
throws IllegalArgumentException,
ArrayIndexOutOfBoundsException
Array類中開辟新的數組:
public static Object newInstance(Class<?> componentType,
int... dimensions)
throws IllegalArgumentException,
NegativeArraySizeException
取得數組信息並修改內容:
package org.chen.yuan.reflect; import java.lang.reflect.Array ; public class ClassArrayDemo{ public static void main(String args[]) throws Exception{ int temp[] = {1,2,3} ;// 聲明一整型數組 Class<?> c = temp.getClass().getComponentType() ; // 取得數組的Class對象 System.out.println("類型:" + c.getName()) ; // 取得數組類型名稱 System.out.println("長度:" + Array.getLength(temp)) ; System.out.println("第一個內容:" + Array.get(temp,0)) ; Array.set(temp,0,6) ; System.out.println("第一個內容:" + Array.get(temp,0)) ; } };輸出:
類型:int
長度:3
第一個內容:1
第一個內容:6
數組修改的過程,實際上就是創建一個新的數組的過程,所以要把舊的數組內容拷貝到新的數組中去。
package org.chen.yuan.reflect; import java.lang.reflect.Array; public class ChangeArrayDemo { public static void main(String args[]) throws Exception { int temp[] = {1, 2, 3};// 聲明一整型數組 int newTemp[] = (int[]) arrayInc(temp, 5); // 重新開辟空間5 print(newTemp); System.out.println("\n-------------------------"); String t[] = {"chenyuan", "wuqing", "lengxue"}; String nt[] = (String[]) arrayInc(t, 8); print(nt); } public static Object arrayInc(Object obj, int len) { Class<?> c = obj.getClass(); Class<?> arr = c.getComponentType(); // 得到數組的 Object newO = Array.newInstance(arr, len); // 開辟新的大小 int co = Array.getLength(obj); System.arraycopy(obj, 0, newO, 0, co); // 拷貝內容 return newO; } public static void print(Object obj) { // 數組輸出 Class<?> c = obj.getClass(); if (!c.isArray()) { // 判斷是否是數組 return; } Class<?> arr = c.getComponentType(); System.out.println(arr.getName() + "數組的長度是:" + Array.getLength(obj)); // 輸出數組信息 for (int i = 0; i < Array.getLength(obj); i++) { System.out.print(Array.get(obj, i) + "、"); // 通過Array輸出 } } };
輸出:
nt數組的長度是:5
1、2、3、0、0、
-------------------------
java.lang.String數組的長度是:8
chenyuan、wuqing、lengxue、null、null、null、null、null、