《Java 反射基礎篇》已介紹反射核心 API,但原生反射調用過程繁瑣,尤其對新手極不友好。本文提供一個封裝良好的 ReflectUtils 工具類,讓反射調用像普通方法一樣簡單,並深入講解靜態/非靜態內部類反射的關鍵差異。
工具類涵蓋四大核心場景:
// 1. 靜態方法調用
Class<?> clazz = ReflectUtils.getClazz("com.yuanhh.model.Outer");
ReflectUtils.invokeStaticMethod(clazz, "outerStaticMethod"); // 無參
ReflectUtils.invokeStaticMethod(clazz, "outerStaticMethod", "yuanhh"); // 有參
// 2. 非靜態方法調用
Object obj = ReflectUtils.newInstance("com.yuanhh.model.Outer");
ReflectUtils.invokeMethod(obj, "outerMethod");
ReflectUtils.invokeMethod(obj, "outerMethod", "yuanhh");
// 3. 靜態屬性操作
ReflectUtils.getStaticField(clazz, "outerStaticField");
ReflectUtils.setStaticField(clazz, "outerStaticField", "new value");
// 4. 非靜態屬性操作
ReflectUtils.getField(obj, "outerField");
ReflectUtils.setField(obj, "outerField", "new value");
若需查看類完整結構,可調用 dumpClass(String className) 獲取所有構造器、方法、屬性信息。
以私有類 Outer 為例,展示關鍵方法實現:
public static Object newInstance(Class clazz, Object... constructorArgs) {
if (clazz == null) return null;
int argLen = constructorArgs == null ? 0 : constructorArgs.length;
Class<?>[] parameterTypes = new Class[argLen];
for (int i = 0; i < argLen; i++) {
parameterTypes[i] = constructorArgs[i].getClass();
}
try {
Constructor constructor = clazz.getDeclaredConstructor(parameterTypes);
if (!constructor.isAccessible()) constructor.setAccessible(true);
return constructor.newInstance(constructorArgs);
} catch (Exception e) { e.printStackTrace(); }
return null;
}
public static Object invokeMethod(Object object, String methodName, Object... methodArgs) {
if (object == null) return null;
try {
Method method = object.getClass().getDeclaredMethod(methodName, obj2class(methodArgs));
if (method != null && !method.isAccessible()) method.setAccessible(true);
return method.invoke(object, methodArgs);
} catch (Exception e) { e.printStackTrace(); }
return null;
}
// 讀取實例屬性
public static Object getField(Object object, String fieldName) { ... }
// 寫入靜態屬性
public static boolean setStaticField(Class clazz, String fieldName, Object value) { ... }
內部類分為 靜態內部類 與 非靜態內部類,反射方式截然不同,核心在於構造器簽名差異。
定義外部類 Outer 包含兩個內部類:
Inner(非靜態)StaticInner(靜態)通過 dumpClass() 對比發現:
private void com.yuanhh.model.Outer$StaticInner()private com.yuanhh.model.Outer$Inner(com.yuanhh.model.Outer) —— 多一個外部類引用參數final Outer this$0 欄位儲存外部實例引用類名格式統一採用 Outer$Inner 形式($ 符號連接)。
與普通類完全一致,直接使用 Outer$StaticInner 作為類名:
Class<?> clazz = ReflectUtils.getClazz("com.yuanhh.model.Outer$StaticInner");
Object obj = ReflectUtils.newInstance("com.yuanhh.model.Outer$StaticInner");
// 後續調用同 1.1 節
關鍵差異:實例化時必須傳入外部類實例
// 1. 先獲取外部類實例
Object outObj = ReflectUtils.newInstance("com.yuanhh.model.Outer");
// 2. 實例化內部類,構造器參數傳入外部實例
Object obj = ReflectUtils.newInstance("com.yuanhh.model.Outer$Inner", outObj);
// 3. 後續調用非靜態方法/屬性
ReflectUtils.invokeMethod(obj, "innerMethod");
ReflectUtils.getField(obj, "innerField");
注意:非靜態內部類不能定義靜態方法/屬性(常量除外),故無靜態操作場景。
ReflectUtils 靜態方法完成,屏蔽底層繁瑣 API。$ 連接;非靜態內部類實例化必須傳外部實例。完整 ReflectUtils 源碼及測試用例即將開源發布,敬請期待。