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

Java 反射機制深度解析:核心類、動態調用與實戰應用

     編輯:Java 相關知識

前言

Java 反射機制是 Java 語言的一項核心特性,它允許程式在執行期動態地獲取類的內部資訊(如建構子、屬性、方法),並能實例化物件、呼叫方法、存取欄位。這種「編譯期不知類型,執行期動態綁定」的能力,是 Spring、Hibernate 等主流框架實現解耦、依賴注入、ORM 映射的基石。本文將系統梳理反射的核心 API、基本操作步驟、程式碼實戰示例,並以 Hibernate 為例剖析其在實際框架中的應用場景。

一、反射核心四大類

Java 反射 API 主要位於 java.lang.reflect 套件中,核心由四個類組成,它們共同構成了類結構的完整視圖:

  • Class:代表類別本身,是反射的入口,包含類別的所有元數據。
  • Constructor:代表類別的建構子,可用於動態建立實例。
  • Field:代表類別的成員變數(屬性),可動態讀寫屬性值。
  • Method:代表類別的方法,可動態呼叫方法並傳遞參數。

二、Class 類常用獲取成員的方法

1. 獲取建構子

方法說明
getConstructor(Class[] params)獲取指定參數類型的 public 建構子
getConstructors()獲取所有 public 建構子
getDeclaredConstructor(Class[] params)獲取指定參數類型的建構子(含 private/protected)
getDeclaredConstructors()獲取所有宣告的建構子(不受修飾符限制)

2. 獲取欄位

方法說明
getField(String name)獲取指定名稱的 public 欄位
getFields()獲取所有 public 欄位
getDeclaredField(String name)獲取指定名稱的宣告欄位(含私有)
getDeclaredFields()獲取所有宣告的欄位

3. 獲取方法

方法說明
getMethod(String name, Class[] params)獲取指定參數類型的 public 方法
getMethods()獲取所有 public 方法(含繼承)
getDeclaredMethod(String name, Class[] params)獲取指定參數類型的宣告方法(含私有)
getDeclaredMethods()獲取所有宣告的方法

三、反射基本操作三步驟

  1. 獲取 Class 物件:三種常見方式
    • Class.forName("全限定類名") —— 最常用,支援動態載入
    • 類名.class —— 編譯期已知類型時使用
    • 物件.getClass() —— 已有實例時使用
  2. 獲取目標成員:呼叫上述 getDeclaredMethod、getDeclaredField 等方法,並對私有成員呼叫 setAccessible(true) 破壞封裝。
  3. 執行實際操作:如 constructor.newInstance(args)、method.invoke(obj, args)、field.set(obj, value) 等。

四、實戰程式碼示例

1. 動態呼叫建構子建立實例

import java.lang.reflect.*;

public class ConstructorDemo {
    public ConstructorDemo() {}
    public ConstructorDemo(int a, int b) {
        System.out.println("a=" + a + ", b=" + b);
    }
    public static void main(String[] args) throws Exception {
        Class cls = Class.forName("ConstructorDemo");
        Class[] paramTypes = {int.class, int.class};
        Constructor ct = cls.getConstructor(paramTypes);
        Object instance = ct.newInstance(37, 47);
    }
}

2. 動態讀寫私有欄位

import java.lang.reflect.*;

public class FieldDemo {
    private double d;
    public static void main(String[] args) throws Exception {
        Class cls = Class.forName("FieldDemo");
        Field fld = cls.getDeclaredField("d");
        fld.setAccessible(true); // 關鍵:暴力反射
        FieldDemo obj = new FieldDemo();
        System.out.println("修改前 d = " + fld.getDouble(obj));
        fld.setDouble(obj, 12.34);
        System.out.println("修改後 d = " + fld.getDouble(obj));
    }
}

3. 動態呼叫方法

import java.lang.reflect.*;

public class MethodDemo {
    public int add(int a, int b) { return a + b; }
    public static void main(String[] args) throws Exception {
        Class cls = Class.forName("MethodDemo");
        Method meth = cls.getMethod("add", int.class, int.class);
        MethodDemo obj = new MethodDemo();
        Object result = meth.invoke(obj, 37, 47);
        System.out.println("結果: " + result); // 輸出 84
    }
}

五、實戰場景:Hibernate 如何利用反射實現 ORM

Hibernate 作為經典的 ORM 框架,其核心任務是將 Java 物件自動持久化到資料庫。由於框架編譯期完全不知道使用者會定義哪些實體類,必須依靠反射在執行期動態分析類結構。

典型流程:從 ResultSet 填充實體物件

  1. 根據查詢 SQL 執行 PreparedStatement,獲得 ResultSet。
  2. 讀取映射配置(XML 或註解),獲取實體類的屬性名稱陣列 String[] props 及其類型。
  3. 獲取實體類的 Class 物件:Class clazz = entity.getClass();。
  4. 遍歷屬性陣列,對每個屬性:
    • 拼裝 Setter 方法名:set + 屬性名首字母大寫。
    • 根據類型從 ResultSet 取值:rs.getInt(i)、rs.getString(i) 等。
    • 反射呼叫 Setter:method.invoke(entity, value)。

這就是「無須硬編碼即可操作任意類」的反射威力。缺點是效能較直接呼叫略低,且破壞封裝需注意安全性,但框架層面通常可透過快取 Method 物件、使用 MethodHandle 或字節碼生成(如 CGLIB、ByteBuddy)優化。

六、總結

Java 反射機制賦予了語言極大的動態性,是框架開發的利器。掌握 Class、Constructor、Field、Method 四大核心類及其常用 API,理解「獲取 Class → 獲取成員 → 執行操作」三步驟,並能結合實際場景(如 ORM、依賴注入、動態代理)靈活運用,是進階 Java 開發者的必備技能。

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