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

Java 反射機制深度解析:從核心概念到實戰應用全景指南

     編輯:Java 相關知識

反射是 Java 語言的核心特性之一,賦予程序在運行時檢查、修改自身結構與行為的能力。這種「自省」機制讓框架開發、動態代理、插件架構成為可能。本文系統梳理反射核心 API,並通過 9 個實戰示例覆蓋類信息獲取、方法調用、對象創建、字段操作、數組處理等全場景。

核心概念

  • java.lang.Class:運行時類型標識,反射入口
  • java.lang.reflect.*:Method、Constructor、Field、Array 等元數據建模類
  • 三步走流程:獲取 Class 對象 → 獲取成員元數據 → 操作目標對象

獲取 Class 對象的三種方式

// 1. 類字面量(編譯期已知)
Class<String> c1 = String.class;

// 2. 對象實例獲取(運行期已知)
String s = "hello";
Class<?> c2 = s.getClass();

// 3. 全限定名動態加載(最常用,框架核心模式)
Class<?> c3 = Class.forName("java.lang.String");

// 基本類型對應的 Class
Class<Integer> c4 = Integer.TYPE;  // 等同於 int.class

示例 1:列出類的所有聲明方法

import java.lang.reflect.*;

public class DumpMethods {
    public static void main(String[] args) {
        try {
            Class<?> c = Class.forName(args[0]);  // 如 java.util.Stack
            Method[] methods = c.getDeclaredMethods();
            for (Method m : methods) {
                System.out.println(m.toString());
            }
        } catch (Throwable e) { e.printStackTrace(); }
    }
}

輸出:包含修飾符、返回類型、方法名、參數列表、異常聲明的完整簽名。

示例 2:模擬 instanceof 操作符

Class<?> cls = Class.forName("A");
boolean b1 = cls.isInstance(new Integer(37));  // false
boolean b2 = cls.isInstance(new A());          // true

示例 3:深度解析方法元數據

Class<?> cls = Class.forName("method1");
Method[] methods = cls.getDeclaredMethods();
for (Method m : methods) {
    System.out.println("name = " + m.getName());
    System.out.println("decl class = " + m.getDeclaringClass());
    for (Class<?> p : m.getParameterTypes()) 
        System.out.println("param = " + p);
    for (Class<?> e : m.getExceptionTypes()) 
        System.out.println("exc = " + e);
    System.out.println("return type = " + m.getReturnType());
    System.out.println("-----");
}

關鍵區別:getDeclaredMethods() 僅獲取當前類聲明方法(含 private);getMethods() 獲取所有 public 方法(含繼承)。

示例 4:構造器信息獲取與動態實例化

Class<?> cls = Class.forName("constructor1");
Constructor<?>[] ctors = cls.getDeclaredConstructors();
for (Constructor<?> ct : ctors) {
    System.out.println("name = " + ct.getName());
    for (Class<?> p : ct.getParameterTypes()) 
        System.out.println("param = " + p);
}

// 動態調用帶參構造器
Class<?>[] paramTypes = {int.class, double.class};
Constructor<?> ct = cls.getConstructor(paramTypes);
Object obj = ct.newInstance(37, 3.14);

示例 5:字段(屬性)完整掃描

Class<?> cls = Class.forName("field1");
Field[] fields = cls.getDeclaredFields();
for (Field f : fields) {
    System.out.println("name = " + f.getName());
    System.out.println("type = " + f.getType());
    System.out.println("modifiers = " + Modifier.toString(f.getModifiers()));
}

Modifier 工具類:將修飾符位掩碼轉為規範字符串(如 public static final)。

示例 6:按名稱動態調用方法

Class<?> cls = Class.forName("method2");
Method add = cls.getMethod("add", int.class, int.class);
Object result = add.invoke(new method2(), 37, 47);  // 返回 Integer(84)

核心場景:方法名在運行期確定(如插件系統、RPC 框架、脚本引擎)。

示例 7:動態創建對象實例

Constructor<?> ct = cls.getConstructor(int.class, int.class);
Object instance = ct.newInstance(37, 47);  // 等同於 new Constructor2(37, 47)

實現工廠模式、依賴注入容器的基礎機制。

示例 8:運行時修改字段值

Field f = cls.getField("d");  // 僅能獲取 public 字段
Field f2 = cls.getDeclaredField("privateField");  // 可獲取私有字段
f2.setAccessible(true);  // 破壞封裝,慎用
f2.setDouble(obj, 12.34);

安全警示:setAccessible(true) 受 SecurityManager 限制,模塊化系統(JPMS)可能禁止深度反射。

示例 9:動態數組操作

// 一維數組
Class<String> cls = String.class;
Object arr = Array.newInstance(cls, 10);
Array.set(arr, 5, "test");
String val = (String) Array.get(arr, 5);

// 三維數組
int[] dims = {5, 10, 15};
Object arr3d = Array.newInstance(int.class, dims);
Array.setInt(Array.get(Array.get(arr3d, 3), 5), 10, 37);
int[][][] cast = (int[][][]) arr3d;
System.out.println(cast[3][5][10]);  // 37

本質:多維數組是數組的數組,Array.get 逐層降維。

反射最佳實踐與避坑指南

場景建議
高頻調用緩存 Method/Constructor/Field 對象,避免重複 getMethod 開銷
性能敏感考慮 MethodHandle / VarHandle(Java 7+)或代碼生成
安全環境避免 setAccessible(true),優先使用公共 API
模塊化導出包 opens com.xxx to java.base 允許深度反射
異常處理捕獲 ReflectiveOperationException 父類統一處理

總結

反射打破了編譯期靜態綁定,是 Spring、Hibernate、MyBatis 等框架的基石。掌握 Class、Method、Constructor、Field、Array 五大核心類協作模式,能讓你從框架使用者進階為框架設計者。但請記住:反射威力巨大,代價是性能、安全與可維護性的妥協,非必要勿濫用。

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