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

Java 動態編程第 2 部分:反射 API 基礎與效能分析

     編輯:Java 相關知識

反射:運行時訪問類元數據的鑰匙

反射 API (java.lang.reflect) 允許程序在運行時檢查類結構、讀寫字段、調用方法、甚至實例化對象,無需編譯時依賴目標類。這種動態性支援插件架構、序列化框架、依賴注入等場景。

核心入口:Class 對象

  • 靜態獲取:Class clazz = MyClass.class;
  • 動態載入:Class.forName("com.example.MyClass") — 觸發類載入與初始化。

常見反射操作

構造器

Class[] types = {String.class, String.class};
Constructor cons = TwoString.class.getConstructor(types);
TwoString ts = cons.newInstance(new Object[]{"a", "b"});

或使用 clazz.newInstance() 快速調用無參構造器(需為 public)。

字段訪問

Field field = obj.getClass().getDeclaredField("name");
field.setAccessible(true); // 繞過訪問控制
int value = field.getInt(obj) + 1;
field.setInt(obj, value);

getDeclaredField 可訪問私有字段,getField 僅限 public 且包含繼承字段。

方法調用

Method method = clazz.getMethod("setCount", int.class);
method.invoke(obj, new Integer(42));

參數與返回值自動進行基本類型與包裝類型轉換。

陣列操作

使用 java.lang.reflect.Array 靜態方法創建、讀寫陣列,如動態擴容:

Class compType = array.getClass().getComponentType();
Object grown = Array.newInstance(compType, newSize);
System.arraycopy(array, 0, grown, 0, Math.min(Array.getLength(array), newSize));

安全性與 AccessibleObject

反射默認遵守 Java 訪問修飾符。AccessibleObject.setAccessible(true) 可關閉檢查,但受 SecurityManager 限制。若啟用安全管理器且無權限,將拋出 SecurityException。

效能基準測試:反射 vs 直接調用

測試環境:1GHz PIII,Linux,循環 1000 萬次。結果(對數坐標):

  • 字段讀寫:反射比直接訪問慢 700~1000 倍 (Sun JVM 1.3/1.4),IBM JVM 約快 2 倍但仍慢數百倍。
  • 方法調用:反射慢 30~數百倍,帶參數調用因裝箱/拆箱開銷更大。
  • 實例創建:newInstance() 慢 2~12 倍;Array.newInstance 慢約 2 倍。

Sun 1.4.1 對反射調用優化顯著,但仍遠慢於直接代碼。

使用建議

  1. 避免在效能關鍵路徑使用反射 — 僅用於啟動配置、框架膠水代碼等低頻場景。
  2. 文檔化反射用途 — 反射繞過靜態類型檢查,增加維護難度,需在代碼註解說明目標類與調用意圖。
  3. 考慮替代方案 — 接口回調、代碼生成、MethodHandle (Java 7+) 等在某些場景更高效。

下一步:實戰反射 — 命令行參數解析庫

下一部分將展示一個利用反射自動映射命令行參數到對象字段的實用庫,體現反射在「配置映射」場景的優勢。

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