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

Java 反射機制建立物件完整實戰:從無參構造到私有欄位操作

     編輯:Java 相關知識

Java 反射允許執行期動態載入類別、建立實例、呼叫方法、存取欄位,甚至突破 private 封裝。本文以完整可執行範例碼,系統講解四大核心場景:無參構造實例化、有參構造實例化、方法呼叫(含私有)、欄位操作(含私有),並總結反射建立物件的標準流程與注意事項。

範例基礎類別


package test;

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public Person() {}

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
    
    private void test() { System.out.println("private method"); }
}

核心場景實作

1. 無參構造實例化(最常用)


public static void createObj1() throws Exception {
    // 方式一:Class.forName 載入類別(支援動態類別名)
    Class clazz = Class.forName("test.Person");
    
    // 方式二:類別字面常數(編譯期已知類別)
    // Class clazz = Person.class;
    
    Object obj = clazz.newInstance(); // 呼叫無參構造子
    System.out.println("是否為 Person 實例:" + (obj instanceof Person));
}

2. 有參構造實例化


public static void createObj2() throws Exception {
    Class clazz = Person.class;
    
    // 取得對應參數型別的 Constructor 物件
    Constructor<Person> constructor = clazz.getConstructor(String.class, int.class);
    
    // 透過 Constructor 建立實例
    Person person = constructor.newInstance("測試", 23);
    System.out.println("建立物件 name:" + person.getName());
}

3. 呼叫方法(含私有方法)


public static void methodDo() throws Exception {
    Person p = new Person();
    Class clazz = Person.class;
    
    // 呼叫 public 方法
    Method setName = clazz.getMethod("setName", String.class);
    setName.invoke(p, "ckl");
    System.out.println("呼叫 setName 後:" + p.getName());
    
    // 呼叫 private 方法:必須用 getDeclaredMethod + setAccessible
    Method privateMethod = clazz.getDeclaredMethod("test");
    privateMethod.setAccessible(true); // 關鍵:暴力反射突破封裝
    privateMethod.invoke(p);
}

4. 操作欄位(含私有欄位)


public static void fieldDo() throws Exception {
    Person p = new Person();
    Class clazz = Person.class;
    
    Field nameField = clazz.getDeclaredField("name");
    Field ageField = clazz.getDeclaredField("age");
    
    nameField.setAccessible(true);
    ageField.setAccessible(true);
    
    nameField.set(p, "反射測試");
    ageField.set(p, 23);
    
    System.out.println("name:" + p.getName() + ",age:" + p.getAge());
}

反射建立物件標準流程總結

  1. 取得 Class 物件:Class.forName("完整類別名")、類別名.class、實例.getClass()、基本型別 int.class/Integer.TYPE。
  2. 選擇實例化策略:
    • 無參構造:clazz.newInstance()(已棄用,建議改用 clazz.getDeclaredConstructor().newInstance())。
    • 有參構造:clazz.getConstructor(參數型別...).newInstance(實參...)。
  3. 型別轉換:(目標類別) 物件 以獲得編譯期型別安全。

取得 Class 物件的四種方式


// 1. 類別字面常數(最常用、編譯期檢查)
Class c1 = String.class;

// 2. Class.forName(動態載入、支援變數)
Class c2 = Class.forName("java.lang.String");

// 3. 實例 getClass()
String s = "hello";
Class c3 = s.getClass();

// 4. 基本型別與包裝類關係
Class c4 = int.class;        // 基本型別
Class c5 = Integer.TYPE;     // 等同 int.class
Class c6 = Integer.class;    // 包裝類

實務注意事項

  • 效能開銷:反射涉及動態解析、存取檢查、裝箱拆箱,比直接呼叫慢 10-100 倍。熱點路徑避免使用,或快取 Method/Field/Constructor 物件。
  • 安全性:setAccessible(true) 受 SecurityManager 限制,模組化系統(JPMS)需在 module-info.java 開放 opens。
  • 泛型擦除:反射取得的泛型資訊有限,複雜泛型需用 TypeToken / ParameterizedType 處理。
  • 模組化封裝:Java 9+ 強制封裝內部 API,反射 JDK 內部類別需 --add-opens 啟動參數。

進階應用場景

  • 框架開發:Spring IoC、MyBatis Mapper 掃描、Jackson 序列化皆大量使用反射。
  • 測試工具:JUnit/Mockito 透過反射注入測試雙、驗證私有狀態。
  • 熱插拔/動態載入:外掛系統、Script 引擎整合。
  • 相容性層:針對不同版本庫動態適配 API 差異。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved