一、 通過反射調用類中的方法
在正常情況下,得到類的對象后,我們就可以直接調用類中的方法了,如果要想調用的話,則肯定必須清楚地知道要調用的方法是什么,之后通過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、
