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

Java 反射機制深度解析:運行時檢查類別、呼叫方法、存取欄位

     編輯:Java 相關知識

反射 API 核心能力

java.lang.reflect 讓程式在運行時動態:

  • 獲取類別結構(修飾詞、父類、介面、建構子、方法、欄位、註解)
  • 建立實例(類別名稱由配置/參數決定)
  • 存取/修改私有欄位
  • 動態呼叫方法(含私有)
  • 動態產生 Proxy、載入類別

廣泛應用於:IDE、除錯器、ORM、DI 容器、序列化、測試框架、插件系統。

實戰範例

1. 分析類別基本資訊

public class Employee {
    public String empNum;
    public String empName;
    public Employee() { this("1", "King"); }
    public Employee(String num, String name) { empNum = num; empName = name; }
    public String toString() { return "Emp: " + empNum + ", " + empName; }
}

import java.lang.reflect.*;

public class AnalyzeClass {
    public static void main(String[] args) {
        Employee e = new Employee();
        Class<?> clazz = e.getClass();
        System.out.println("類別名稱: " + clazz.getName());
        System.out.println("父類別: " + clazz.getSuperclass().getName());
        int mods = clazz.getModifiers();
        System.out.println("public: " + Modifier.isPublic(mods));
        System.out.println("final: " + Modifier.isFinal(mods));
        System.out.println("abstract: " + Modifier.isAbstract(mods));
    }
}

2. 列出所有方法

public class DumpMethods {
    public static void main(String[] args) throws Exception {
        Class<?> c = Class.forName(args[0]); // 傳入 java.util.Stack
        for (Method m : c.getDeclaredMethods()) {
            System.out.println(m);
        }
    }
}
// 輸出範例:
// public synchronized java.lang.Object java.util.Stack.pop()
// public java.lang.Object java.util.Stack.push(java.lang.Object)
// public boolean java.util.Stack.empty()
// ...

3. 列出所有欄位

public class DumpFields {
    public static void main(String[] args) throws Exception {
        Class<?> c = Class.forName(args[0]); // 傳入 Employee
        for (Field f : c.getDeclaredFields()) {
            System.out.println(f);
        }
    }
}
// 輸出:
// public java.lang.String Employee.empNum
// public java.lang.String Employee.empName

4. 列出建構子與參數類型

public class DumpConstructors {
    public static void main(String[] args) throws Exception {
        Class<?> c = Class.forName(args[0]);
        for (Constructor<?> cons : c.getDeclaredConstructors()) {
            System.out.println(cons);
            for (Class<?> pt : cons.getParameterTypes()) {
                System.out.println("  參數: " + pt.getName());
            }
        }
    }
}
// 輸出:
// public Employee(java.lang.String,java.lang.String)
//   參數: java.lang.String
//   參數: java.lang.String
// public Employee()

5. 運行時動態呼叫方法

public class DynamicInvoke {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("com.example.MyService");
        Object instance = clazz.getDeclaredConstructor().newInstance();
        Method m = clazz.getMethod("setProperties", Properties.class);
        Properties props = new Properties();
        props.setProperty("key", "value");
        m.invoke(instance, props);
    }
}

效能與安全考量

面向影響建議
效能反射比直接呼叫慢 10-100 倍熱點路徑快取 Method/Field/Constructor 物件;JDK 7+ MethodHandle 更快
安全性可破壞封裝、繞過泛型檢查SecurityManager 限制 suppressAccessChecks;模組化 (JPMS) 封裝內部 API
維護性編譯期無法檢查字串名稱善用常數、註解驅動、框架封裝

最佳實務

  • 優先使用介面/抽象類別 + DI 容器,減少直接反射
  • 若必須反射,封裝為工具類,集中處理異常與快取
  • JDK 9+ 使用 java.lang.invoke.MethodHandles.lookup() 取代部分反射
  • 模組系統下需在 module-info.java 宣告 opens 才能深度反射
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved