| 目標 | Class 方法 | 返回類型 | 說明 |
|---|---|---|---|
| 所有 public 成員(含繼承) | getFields() | Field[] | 僅 public,包含父類 |
| 本類宣告的所有成員 | getDeclaredFields() | Field[] | 包含 private/protected,不含繼承 |
| 所有 public 建構子 | getConstructors() | Constructor[] | 僅 public |
| 本類宣告的所有建構子 | getDeclaredConstructors() | Constructor[] | 包含 private/protected |
package com.example.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class ReflectDemo {
public static void main(String[] args) {
// 1. 獲取 Class 物件的三種方式
Class<?> clazz1 = String.class; // 方式一:類字面常量
Class<?> clazz2 = "hello".getClass(); // 方式二:實例.getClass()
Class<?> clazz3 = null;
try {
clazz3 = Class.forName("java.lang.String"); // 方式三:完整類名
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 2. 列印類別基本資訊
printClassInfo(clazz1);
// 3. 列印所有宣告的成員屬性
printDeclaredFields(clazz1);
// 4. 列印所有宣告的建構子
printDeclaredConstructors(clazz1);
// 5. 實戰:動態建立實例並存取私有欄位
demonstratePrivateAccess();
}
/** 列印類別基本資訊 */
static void printClassInfo(Class<?> clazz) {
System.out.println("========== 類別資訊 ==========");
System.out.println("完整類名:" + clazz.getName());
System.out.println("簡單類名:" + clazz.getSimpleName());
System.out.println("包名:" + clazz.getPackageName());
System.out.println("修飾符:" + Modifier.toString(clazz.getModifiers()));
System.out.println("父類別:" + clazz.getSuperclass().getName());
System.out.println("實作介面:" + java.util.Arrays.toString(clazz.getInterfaces()));
System.out.println("是否為介面:" + clazz.isInterface());
System.out.println("是否為陣列:" + clazz.isArray());
System.out.println("是否為基本類型:" + clazz.isPrimitive());
System.out.println("是否為枚舉:" + clazz.isEnum());
System.out.println("是否為註解:" + clazz.isAnnotation());
}
/** 列印宣告的成員屬性 */
static void printDeclaredFields(Class<?> clazz) {
System.out.println("\n========== 宣告的成員屬性 ==========");
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
String modifiers = Modifier.toString(field.getModifiers());
String typeName = field.getType().getSimpleName();
String fieldName = field.getName();
System.out.printf("%-15s %-20s %s%n", modifiers, typeName, fieldName);
}
}
/** 列印宣告的建構子 */
static void printDeclaredConstructors(Class<?> clazz) {
System.out.println("\n========== 宣告的建構子 ==========");
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
for (Constructor<?> ctor : constructors) {
String modifiers = Modifier.toString(ctor.getModifiers());
String paramTypes = java.util.Arrays.stream(ctor.getParameterTypes())
.map(Class::getSimpleName)
.collect(java.util.stream.Collectors.joining(", "));
System.out.printf("%-15s %s(%s)%n", modifiers, clazz.getSimpleName(), paramTypes);
}
}
/** 示範存取私有欄位與呼叫私有建構子 */
static void demonstratePrivateAccess() {
System.out.println("\n========== 私有存取示範 ==========");
try {
Class<?> clazz = Class.forName("java.lang.String");
// 1. 獲取私有建構子並建立實例
Constructor<?> ctor = clazz.getDeclaredConstructor(char[].class, boolean.class);
ctor.setAccessible(true); // 關鍵:暴力反射破壞封裝
Object strObj = ctor.newInstance(new char[]{'H', 'i'}, true);
System.out.println("透過私有建構子建立:" + strObj);
// 2. 存取私有欄位 value (String 內部 char[] 欄位,JDK 9+ 為 byte[])
Field valueField = clazz.getDeclaredField("value");
valueField.setAccessible(true);
Object value = valueField.get(strObj);
System.out.println("私有欄位 value 內容:" + java.util.Arrays.toString((Object[]) value));
} catch (Exception e) {
System.err.println("反射操作失敗:" + e.getMessage());
}
}
}
========== 類別資訊 ========== 完整類名:java.lang.String 簡單類名:String 包名:java.lang 修飾符:public final 父類別:java.lang.Object 實作介面:[interface java.io.Serializable, interface java.lang.Comparable, interface java.lang.CharSequence] 是否為介面:false 是否為陣列:false 是否為基本類型:false 是否為枚舉:false 是否為註解:false ========== 宣告的成員屬性 ========== final byte[] value static Comparator CASE_INSENSITIVE_ORDER private static long serialVersionUID private int hash private static ObjectStreamField[] serialPersistentFields ========== 宣告的建構子 ========== public String(char[], boolean) public String(byte[], int, int, java.nio.charset.Charset) public String(byte[], int, int) ... (共 15 個建構子) ========== 私有存取示範 ========== 透過私有建構子建立:Hi 私有欄位 value 內容:[H, i]
private、protected、package-private 成員。SecurityManager 允許 suppressAccessChecks 權限(生產環境通常關閉 SecurityManager)。module-info.java 開放 opens com.example to java.base 或命令列 --add-opens。// 精確匹配參數類型順序 Constructor<?> ctor = clazz.getDeclaredConstructor(String.class, int.class, boolean.class);
反射無法直接獲取執行期泛型參數(如 List<String> 的 String),需透過 Type、ParameterizedType 解析簽名:
Field field = clazz.getDeclaredField("stringList");
Type genericType = field.getGenericType();
if (genericType instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) genericType;
Type[] actualTypes = pt.getActualTypeArguments(); // [class java.lang.String]
}
Field/Method/Constructor 物件,或使用 MethodHandle/VarHandle(JDK 7/9+)。sun.misc.*、com.sun.*)預設封裝,需 --add-exports 開放。module-info.java 宣告 opens 允許反射:module com.myapp {
opens com.myapp.model to java.base, spring.core;
// 或無條件開放
opens com.myapp.model;
}