使用java反射操作類的建構函式,成員變數和成員方法
阿新 • • 發佈:2019-01-03
在java.lang.reflect包中有三個類Field,Method,Constructor.分別描述域,方法,構造器。參考API,關於這三個類的說明。
在執行時使用反射分析物件,如果訪問的是私有域或是私有方法,私有建構函式,會丟擲IllegalAccessException.因為反射機制的預設行為受限於java的訪問控制,然而,如果一個java程式沒有受到安全管理器的控制,就可以覆蓋訪問控制。為了達到這個目的,需要呼叫Field,Method,Constructor物件的setAccessible方法,setAccessible方法是AccessibleObject類的一個方法,是Field,Method,Constructor類的公共超類。
setAccessible(true);
不要過多地使用反射:破壞類封裝;效率偏低;編譯器不容易幫助發現錯誤,在執行時才會被發現。
我使用反射,是為了寫單元測試程式碼,對執行物件的分析,改變物件的私有域等,達到測試需要的覆蓋率。
以下提供程式碼事例:
測試類:
publicclass RunBing {private String name;
privateint age;
public String sex;
public RunBing() {
}
private RunBing(String name) {
this
}
publicvoid setName(String name) {
this.name = name;
}
publicvoid setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
publicint getAge() {
return age;
}
public String run() {
return
}
private String add() {
return"add method";
}
}
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;
publicclass ReflectHelp {
/**
* 通過構造器取得例項
* @param className 類的全限定名
* @param intArgsClass 建構函式的引數型別
* @param intArgs 建構函式的引數值
*
* @return Object
*/
publicstatic Object getObjectByConstructor(String className,Class[] intArgsClass,Object[] intArgs){
Object returnObj=null;
try{
Class classType = Class.forName(className);
Constructor constructor = classType.getDeclaredConstructor(intArgsClass); //找到指定的構造方法
constructor.setAccessible(true);//設定安全檢查,訪問私有建構函式必須
returnObj = constructor.newInstance(intArgs);
}catch (NoSuchMethodException ex) {
ex.printStackTrace();
}catch (Exception ex) {
ex.printStackTrace();
}
return returnObj;
}
/**
* 修改成員變數的值
* @param Object 修改物件
* @param filedName 指定成員變數名
* @param filedValue 修改的值
*
* @return
*/
publicstaticvoid modifyFileValue(Object object, String filedName,
String filedValue) {
Class classType = object.getClass();
Field fild =null;
try{
fild = classType.getDeclaredField(filedName);
fild.setAccessible(true);//設定安全檢查,訪問私有成員變數必須
fild.set(object, filedValue);
}catch (NoSuchFieldException ex) {
ex.printStackTrace();
}catch (Exception ex) {
ex.printStackTrace();
}
}
/**
* 訪問類成員變數
* @param Object 訪問物件
* @param filedName 指定成員變數名
* @return Object 取得的成員變數的值
* */
publicstatic Object getFileValue(Object object, String filedName) {
Class classType = object.getClass();
Field fild =null;
Object fildValue =null;
try{
fild = classType.getDeclaredField(filedName);
fild.setAccessible(true);//設定安全檢查,訪問私有成員變數必須
fildValue = fild.get(object);
}catch (NoSuchFieldException ex) {
ex.printStackTrace();
}catch (Exception ex) {
ex.printStackTrace();
}
return fildValue;
}
/**
* 呼叫類的方法,包括私有
* @param Object 訪問物件
* @param methodName 指定成員變數名
* @param type 方法引數型別
* @param value 方法引數指
* @return Object 方法的返回結果物件
* */
publicstatic Object useMethod(Object object, String methodName,
Class[] type, Class[] value) {
Class classType = object.getClass();
Method method =null;
Object fildValue =null;
try{
method = classType.getDeclaredMethod(methodName, type);
method.setAccessible(true);//設定安全檢查,訪問私有成員方法必須
fildValue = method.invoke(object, value);
}catch (NoSuchMethodException ex) {
ex.printStackTrace();
}catch (Exception ex) {
ex.printStackTrace();
}
return fildValue;
}
publicstaticvoid main(String[] args) {
RunBing runbing =new RunBing();
runbing.setName("aaa");
//訪問成員變數
String value = (String) ReflectHelp.getFileValue(runbing, "sex");
System.out.println("value:"+ value);
//修改成員變數
ReflectHelp.modifyFileValue(runbing, "sex", "bbb");
System.out.println("value:"+ runbing.getName());
//檢查修改後的變數值
value = (String) ReflectHelp.getFileValue(runbing, "sex");
System.out.println("value:"+ value);
//呼叫方法
value = (String) ReflectHelp.useMethod(runbing, "add", new Class[] {},
new Class[] {});
System.out.println("value:"+ value);
//使用指定建構函式
Class[] inArgs =new Class[]{String.class};
Object[] inArgsParms =new Object[]{"hanj"};
RunBing runBing2 = (RunBing)ReflectHelp.getObjectByConstructor("com.ccit.hj.reflect.RunBing",inArgs,inArgsParms);
value = (String) ReflectHelp.getFileValue(runBing2, "name");
System.out.println("cc -- value:"+ value);
}