首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 反射實戰篇:ReflectUtils 工具類與內部類反射全解析

     編輯:Java 相關知識

前言

《Java 反射基礎篇》已介紹反射核心 API,但原生反射調用過程繁瑣,尤其對新手極不友好。本文提供一個封裝良好的 ReflectUtils 工具類,讓反射調用像普通方法一樣簡單,並深入講解靜態/非靜態內部類反射的關鍵差異。

一、ReflectUtils 核心功能與用法

工具類涵蓋四大核心場景:

  1. 調用類的靜態方法
  2. 調用類的非靜態方法
  3. Set/Get 類的靜態屬性
  4. Set/Get 類的非靜態屬性

1.1 快速上手示例

// 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) 獲取所有構造器、方法、屬性信息。

1.2 核心源碼解析

以私有類 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) { ... }

二、內部類反射的關鍵差異

內部類分為 靜態內部類 與 非靜態內部類,反射方式截然不同,核心在於構造器簽名差異。

2.1 結構差異深度剖析

定義外部類 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 形式($ 符號連接)。

2.2 靜態內部類反射用法

與普通類完全一致,直接使用 Outer$StaticInner 作為類名:

Class<?> clazz = ReflectUtils.getClazz("com.yuanhh.model.Outer$StaticInner");
Object obj = ReflectUtils.newInstance("com.yuanhh.model.Outer$StaticInner");
// 後續調用同 1.1 節

2.3 非靜態內部類反射用法

關鍵差異:實例化時必須傳入外部類實例

// 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。
  • 內部類關鍵點:類名用 $ 連接;非靜態內部類實例化必須傳外部實例。
  • 適用場景:訪問私有/隱藏(@hide)成員、熱修復、框架開發、動態代理等。

完整 ReflectUtils 源碼及測試用例即將開源發布,敬請期待。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved