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

Java 反射機制全景解析:Class 類操作、動態加載、運行時對象檢查、Method.invoke、泛型擦除與 Array 工具類實戰

     編輯:Java 綜合教學

Java 反射機制全景解析

反射是 Java 動態性的基石,允許運行時檢查類結構、創建實例、調用方法、訪問字段。本文系統涵蓋 Class 類、動態加載、對象檢查、方法調用、泛型擦除驗證、泛型數組創建六大核心場景。

1. Class 類:類的類

每個類在 JVM 中對應一個 Class 實例。獲取方式三種:

// 1. 對象.getClass()
Class cl = obj.getClass();

// 2. Class.forName("全限定名") - 支援字符串動態加載
Class cl = Class.forName("java.util.Date");

// 3. 類字面常量 .class - 編譯期常量
Class cl1 = String.class;
Class cl2 = int.class;      // 基本類型也有 Class
Class cl3 = Double[].class; // 數組類型也有 Class

比較用 ==:obj.getClass() == String.class。getName() 返回全限定名。newInstance() 調用無參構造器創建實例(已棄用,建議用 getDeclaredConstructor().newInstance())。

2. 異常處理模板

try {
    Class cl = Class.forName(className);
    // 使用 cl
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
    e.printStackTrace();
}

3. 運行時分析類結構

java.lang.reflect 三大核心類:

  • Field:getName()、getType()、getModifiers()
  • Method:getName()、getReturnType()、getParameterTypes()、getModifiers()
  • Constructor:getName()、getParameterTypes()、getModifiers()

Modifier.toString(modifiers) 將修飾符位掩碼轉可讀字符串。

獲取成員的兩組方法

方法範圍含繼承
getFields()/getMethods()/getConstructors()public是
getDeclaredFields()/getDeclaredMethods()/getDeclaredConstructors()所有聲明否

打印類完整信息示例

public static void printClassInfo(String className) {
    Class cl = Class.forName(className);
    // 打印類聲明、構造器、方法、字段...
}

輸入 java.lang.String 可見 15 構造器、70+ 方法、5 字段(value/hash/serialVersionUID/serialPersistentFields/CASE_INSENSITIVE_ORDER)。

4. 動態加載類:插件化架構基石

場景:Office 啟動 Word/Excel 組件,Excel 未編譯完成時 Office 仍可編譯運行。

interface OfficeAble { void start(); }

// Office 主程序
Class cl = Class.forName(args[0]); // 動態加載
OfficeAble oa = (OfficeAble) cl.newInstance(); // 創建實例
oa.start(); // 統一接口調用
  • 組件實現 OfficeAble 接口
  • 主程序無需依賴具體組件類
  • 新增組件無需重新編譯主程序

5. 運行時檢查/修改對象字段

關鍵 API

  • Field.get(obj):獲取字段值(返回 Object,基本類型自動裝箱)
  • Field.set(obj, value):設置字段值
  • Field.getDouble(obj) 等類型專用獲取器,避免裝箱

突破訪問控制

Field f = cl.getDeclaredField("privateField");
f.setAccessible(true); // 關鍵:關閉安全檢查
Object val = f.get(obj);
f.set(obj, newValue);

setAccessible(true) 需無 SecurityManager 禁止。

6. Method.invoke:動態方法調用

Method m = cl.getMethod("methodName", String.class, int.class);
m.invoke(targetObj, "arg1", 123); // 實例方法
m.invoke(null, "arg1", 123);      // 靜態方法 targetObj 傳 null
  • 返回值:有返回類型返回 Object,void 返回 null
  • 參數:可變參數 Object... args,基本類型自動裝箱
  • 異常:InvocationTargetException 包裹真實異常,需 getCause()

7. 反射驗證泛型擦除

ArrayList raw = new ArrayList();
ArrayList generic = new ArrayList<>();
System.out.println(raw.getClass() == generic.getClass()); // true

// 繞過編譯器檢查,向 List 添加 Integer
Method add = generic.getClass().getDeclaredMethod("add", Object.class);
add.invoke(generic, 99); // 成功!
System.out.println(generic); // [99]

// 但遍歷時會 ClassCastException
for (String s : generic) { ... } // 運行時拋出異常

結論:泛型僅編譯期檢查,運行期擦除為原始類型。反射可繞過編譯器注入異類數據,但後續使用仍受類型系統約束。

8. java.lang.reflect.Array:動態創建泛型數組

問題:Object[] 無法轉型為 String[]。

public static Object goodCopyOf(Object arr, int newLength) {
    Class cl = arr.getClass();
    if (!cl.isArray()) return null;
    Class componentType = cl.getComponentType(); // 獲取元素類型
    int length = Array.getLength(arr);           // 獲取長度
    Object newArr = Array.newInstance(componentType, newLength); // 創建同類型數組
    System.arraycopy(arr, 0, newArr, 0, Math.min(length, newLength));
    return newArr;
}
  • 參數聲明 Object 而非 Object[],因 int[] 是 Object 子類但非 Object[]
  • Array.newInstance(componentType, length) 動態創建指定類型數組
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved