反射定義
先來看看java反射的三個(gè)階段: 每一個(gè)階段我們都有對(duì)應(yīng)的手段得到字節(jié)碼文件對(duì)象,得到對(duì)應(yīng)的字節(jié)碼文件對(duì)象只是我們反射的第一步,我們真正想做的是改變成員變量的屬性值或者是調(diào)用類中的方法。 反射創(chuàng)建對(duì)象Class c = String.class;
String s = (String) c.newInstance();
一個(gè)字節(jié)碼文件對(duì)象調(diào)用該方法可以創(chuàng)建其實(shí)例對(duì)象,注意此種創(chuàng)建對(duì)象方式只能局限于非私有空參構(gòu)造方法(沒有空參構(gòu)造或者空參構(gòu)造是私有的不能通過此種方法創(chuàng)建對(duì)象)。 Constructor<T> getConstructor(Class<?>... parameterTypes)//根據(jù)指定構(gòu)造參數(shù)類型得到對(duì)應(yīng)的Constructor對(duì)象
Constructor<?>[] getConstructors()//得到包含該類所有public構(gòu)造方法Constructor對(duì)象的數(shù)組
上面的一組方法可以得到public權(quán)限修飾的構(gòu)造方法 Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
Constructor<?>[] getDeclaredConstructors()
在Class類中有一類方法是以getDeclared…開頭的,這一類方法可以得到類中私有的構(gòu)造、屬性和方法。 package com.qj.reflect;
public class ReflectBean {
private ReflectBean() {
super();//私有構(gòu)造
}
public void print(String s) {
System.out.println(s);
}
}
該類私有了構(gòu)造方法,下面通過反射創(chuàng)建對(duì)象并調(diào)用該類中的方法: public static void testConstructor() throws Exception {
Class c = Class.forName('com.qj.reflect.ReflectBean');
Constructor dc = c.getDeclaredConstructor();//得到私有構(gòu)造
dc.setAccessible(true);// 解除私有權(quán)限
ReflectBean rb = (ReflectBean) dc.newInstance();//創(chuàng)建對(duì)象
rb.print('反射創(chuàng)建對(duì)象調(diào)用方法');
}
反射修改屬性值與獲取字節(jié)碼對(duì)象的構(gòu)造方法類似,獲取成員屬性Class類中也有對(duì)應(yīng)的API: Field getField(String name)//根據(jù)屬性名稱獲取Field對(duì)象,僅限public
Field[] getFields()//獲取該類所有的public屬性
Field getDeclaredField(String name)//根據(jù)屬性名稱獲取Field對(duì)象,private屬性也可獲取
Field[] getDeclaredFields()//獲取該類所有的屬性
為了便于演示我們?cè)赗eflectBean類中添加一個(gè)屬性flag private boolean flag = true;
反射修改屬性值: public static void testField() throws Exception {
Class c = Class.forName('com.qj.reflect.ReflectBean');
Constructor dc = c.getDeclaredConstructor();// 得到私有構(gòu)造
dc.setAccessible(true);// 解除私有權(quán)限
ReflectBean rb = (ReflectBean) dc.newInstance();// 創(chuàng)建對(duì)象
Field flag = c.getDeclaredField('flag');//通過屬性flag得到對(duì)應(yīng)的Field對(duì)象
flag.setAccessible(true);// 解除私有權(quán)限
flag.setBoolean(rb, false);//修改屬性值
}
Field類中修改屬性值A(chǔ)PI: set(Object obj, Object value)
setBoolean(Object obj, boolean z)
setByte(Object obj, byte b)
setChar(Object obj, char c)
setDouble(Object obj, double d)
setFloat(Object obj, float f)
setInt(Object obj, int i)
setLong(Object obj, long l)
setShort(Object obj, short s)
反射調(diào)用方法在開發(fā)中經(jīng)常遇到有某個(gè)類的對(duì)象但是方法是私有的,眼巴巴地看著不能調(diào)用,反射的強(qiáng)大之處就是能夠讓你為所欲為! Method getMethod(String name, Class<?>... parameterTypes)
Method[] getMethods()
Method getDeclaredMethod(String name, Class<?>... parameterTypes)
Method[] getDeclaredMethods()
結(jié)合之前對(duì)于構(gòu)造方法和屬性的獲取,Class類中對(duì)方法對(duì)象的獲取就很容易理解了。 private void secret() {
System.out.println('私有方法被調(diào)用了!');
}
利用反射調(diào)用私有方法: public static void testMethod() throws Exception{
Class c = Class.forName('com.qj.reflect.ReflectBean');
Constructor dc = c.getDeclaredConstructor();// 得到私有構(gòu)造
dc.setAccessible(true);// 解除私有權(quán)限
ReflectBean rb = (ReflectBean) dc.newInstance();// 創(chuàng)建對(duì)象
Method dm = c.getDeclaredMethod('secret');//根據(jù)方法名稱獲取Method對(duì)象
dm.setAccessible(true);// 解除私有權(quán)限
dm.invoke(rb);//調(diào)用方法
}
我們向ReflectBean測(cè)試類中添加一個(gè)有參的私有方法: private void secret(String s) {
System.out.println('有參私有方法被調(diào)用了! s : ' s);
}
反射調(diào)用有參私有方法: //Class c , ReflectBean rb 生成步驟略
Method dm = c.getDeclaredMethod('secret', String.class);// 根據(jù)方法名稱及方法參數(shù)類型獲取Method對(duì)象
dm.setAccessible(true);// 解除私有權(quán)限
dm.invoke(rb, '方法參數(shù)內(nèi)容');// 調(diào)用方法
反射工具類package com.qj.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
//反射工具類
public class ReflectUtil {
private ReflectUtil() {
super();
}
/**
* 根據(jù)全類名得到一個(gè)該類的對(duì)象(僅限非私有空參構(gòu)造)
*
* @param className 全類名(形如com.qj.reflect.ReflectBean)
* @return 該類的實(shí)例
* @throws InstantiationException
* @throws IllegalAccessException
* @throws ClassNotFoundException
*/
public static Object newInstance(String className)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
Class c = Class.forName(className);
Object o = c.newInstance();
return o;
}
/**
* 根據(jù)全類名以及構(gòu)造方法參數(shù)得到一個(gè)該類的對(duì)象
*
* @param className 全類名(形如com.qj.reflect.ReflectBean)
* @param args 構(gòu)造方法參數(shù)(可變參數(shù))
* @return 該類的實(shí)例
* @throws ClassNotFoundException
* @throws NoSuchMethodException
* @throws SecurityException
* @throws InstantiationException
* @throws IllegalAccessException
* @throws IllegalArgumentException
* @throws InvocationTargetException
*/
public static Object createInstance(String className, Object... args)
throws ClassNotFoundException, NoSuchMethodException,
SecurityException, InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
Class c = Class.forName(className);
Constructor dc = null;
int length = args.length;
if (args != null && length > 0) {//有參構(gòu)造
Class[] type = new Class[length];
for (int i = 0; i < length; i ) {
type[i] = args[i].getClass();
}
dc = c.getDeclaredConstructor(type);
dc.setAccessible(true);
return dc.newInstance(args);
}
dc = c.getDeclaredConstructor();//無參構(gòu)造
dc.setAccessible(true);
return dc.newInstance();
}
/**
* 根據(jù)傳過來的對(duì)象以及對(duì)象的屬性名稱更改屬性值
*
* @param obj 該類的實(shí)例
* @param fieldName 該類的屬性名稱
* @param value 要更改的屬性值
* @throws NoSuchFieldException
* @throws SecurityException
* @throws IllegalArgumentException
* @throws IllegalAccessException
*/
public static void modfyField(Object obj, String fieldName, Object value)
throws NoSuchFieldException, SecurityException,
IllegalArgumentException, IllegalAccessException {
Class c = obj.getClass();
Field field = c.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
}
/**
* 根據(jù)傳過來的對(duì)象以及對(duì)象的方法名稱調(diào)用該方法
*
* @param obj 該類的實(shí)例
* @param methodName 要調(diào)用的方法
* @param args 方法的參數(shù)(可變參數(shù))
* @throws NoSuchMethodException
* @throws SecurityException
* @throws IllegalAccessException
* @throws IllegalArgumentException
* @throws InvocationTargetException
*/
public static void invokeMethod(Object obj, String methodName,
Object... args) throws NoSuchMethodException, SecurityException,
IllegalAccessException, IllegalArgumentException,
InvocationTargetException {
Class c = obj.getClass();
Method method = null;
if (args != null && args.length > 0) {// 有參方法
Class[] type = new Class[args.length];
for (int i = 0; i < type.length; i ) {
type[i] = args[i].getClass();
}
method = c.getDeclaredMethod(methodName, type);
} else {// 空參方法
method = c.getDeclaredMethod(methodName);
}
method.setAccessible(true);
method.invoke(obj, args);
}
}
有了這個(gè)工具類我們用反射就很easy了: ReflectBean obj = (ReflectBean) ReflectUtil
.createInstance('com.qj.reflect.ReflectBean');//創(chuàng)建對(duì)象
ReflectUtil.modfyField(obj, 'flag', false);// 修改flag屬性值
ReflectUtil.invokeMethod(obj, 'secret');// 調(diào)用secret空參構(gòu)造
ReflectUtil.invokeMethod(obj, 'secret', '太帥了');// 調(diào)用secret有參構(gòu)造
通過使用反射工具類大大減少了代碼量,一句代碼解決一個(gè)問題,清晰明朗。 |
|