什麼是反射
官方有段介紹是這麼說的
Reflection is commonly used by programs which require the ability to examine or modify the runtime behavior of applications running in the Java virtual machine.
什麼意思呢,就是說反射通常用於需要能夠檢查或修改Java虛擬機中運行的應用程序的運行時行爲的程序。
不是很好懂,我們說下反射能做什麼吧。
- 反射可以在運行時動態生成某個類的實例。
- 反射可以在運行時獲取某個類的任何的變量並修改變量的值。
- 反射可以在運行時執行某個類的任何方法。
如何使用反射
我們針對上面的情況一一說一下如何使用。
我們先定義一個 com.reflect.Demo.java 用來做我們後續的實驗。
package com.reflect;
public class Demo {
public String pubStr = "public_string";
private String priStr = "private_string";
private String getPriStr(String testParam) {
pubStr = testParam;
return priStr;
}
private String getPriStr() {
return priStr;
}
public Demo() {
}
private Demo( String priStr ) {
this.priStr = priStr;
}
@Override
public String toString() {
return "Demo{" +
"pubStr='" + pubStr + '\'' +
", priStr='" + priStr + '\'' +
'}';
}
}
在運行時動態生成某個類的實例
// 反射第一步是獲取類的 class , 一般有 3 種寫法
Class demoClass = Class.forName("com.reflect.Demo");
// demoClass = Demo.class;
// demoClass = new Demo().getClass();
// 獲取無參構造函數
Constructor constructor = demoClass.getDeclaredConstructor();
// 設置可以訪問
constructor.setAccessible(true);
// 根據構造方法創建實例
Object demo = constructor.newInstance();
// 獲取有參構造函數
Constructor constructor1 = demoClass.getDeclaredConstructor(String.class);
// 設置可以訪問
constructor1.setAccessible(true);
// 根據構造方法創建實例
Object demo1 = constructor1.newInstance("I am String");
下面介紹一種通用的獲取某個類的實例的方法
/**
* 運用反射,通過默認的構造方法獲取某個類的實例
*
* @param className
* @return
*/
public static Object getObjectInstance(String className, Object... args) {
try {
Class[] classes = new Class[args.length];
for (int i = 0; i < args.length; i++) {
classes[i] = args[i].getClass();
}
Class objClass = Class.forName(className);
Constructor constructor = objClass.getDeclaredConstructor(classes);
constructor.setAccessible(true);
return constructor.newInstance(args);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return new Object();
}
在運行時獲取某個類的任何的變量並修改變量的值
下面的代碼會告訴大家如何獲取 Demo.java 的一個實例的變量 (priStr) 並對其賦值。
// 無參構造方法 new 的實例,裏面的 priStr 值爲 private_string
Demo demo = new Demo();
// 獲取 demo 的 class
Class demoClass = demo.getClass();
// 獲取 priStr 的 Field
Field priStrField = demoClass.getDeclaredField("priStr");
// 設置可以訪問
priStrField.setAccessible(true);
// 取 priStr 的值
// 要取的是 demo 這個實例的 priStr , 所以需要傳入 demo
Object priStrValue = priStrField.get(demo);
// 修改 priStr 的值
// 要修改的是 demo 這個實例, 所以需要傳入 demo
priStrField.set(demo,"I am Private String");
下面介紹一種通用的獲取屬性的方法
/**
* 獲取某個變量的值
*
* @param obj 待取值的類
* @param fieldName 待取值的變量的變量名
* @return
*/
public static Object getFieldValue(Object obj, String fieldName) {
try {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(obj);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return new Object();
}
/**
* 設置某個類的某個變量的值
*
* @param obj
* @param fieldName
* @param fieldValue
* @return
*/
public static boolean setFieldValue(Object obj, String fieldName, Object fieldValue) {
try {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, fieldValue);
return true;
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return false;
}
在運行時執行某個類的任何方法
下面的代碼會告訴大家如何獲取 Demo.java 的一個方法(getPriStr) 並調用此方法。
// 無參構造方法 new 的實例,裏面的 priStr 值爲 private_string
Demo demo = new Demo();
// 獲取 demo 的 class
Class demoClass = demo.getClass();
// 獲取無參 getPriStr 對應的 Method
Method priStrMethod = demoClass.getDeclaredMethod("priStr");
// 設置可以訪問
priStrMethod.setAccessible(true);
// 調用此方法
Object priStr = priStrMethod.invoke(obj);
// 獲取有參 getPriStr 對應的 Method
Method priStrMethod1 = demoClass.getDeclaredMethod("priStr",String.class);
// 設置可以訪問
priStrMethod1.setAccessible(true);
// 調用此方法
Object priStr1 = priStrMethod1.invoke(obj,"I am testParam");
下面介紹一種通用的調用對象的方法
/**
* 調用某個方法
* @param obj
* @param methodName
* @param args
* @return
*/
public static Object invokMethod(Object obj, String methodName, Object... args) {
try {
Class[] classes = new Class[args.length];
for (int i = 0; i < args.length; i++) {
classes[i] = args[i].getClass();
}
Method method = obj.getClass().getDeclaredMethod(methodName, classes);
method.setAccessible(true);
method.invoke(obj,args);
return method.invoke(obj, args);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return new Object();
}
更多用法可參考 DEMO