反射不僅是框架底層技術,更能解決業務層「同類邏輯不同類型重複代碼」問題。本文從基礎 API 入手,逐步構建通用對象描述、動態實例化、字段讀寫、方法調用、跨類型搜索框架,展示反射的工程化應用價值。
核心類:Class、Constructor、Field、Method、Modifier。
關鍵方法:getDeclaredConstructors/Fields/Methods() 獲取聲明成員 (含私有);setAccessible(true) 突破封裝。
public static void describeInstance(Object object) {
Class<?> clazz = object.getClass();
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
Field[] fields = clazz.getDeclaredFields();
Method[] methods = clazz.getDeclaredMethods();
// 輸出構造器、字段、方法詳情
// 關鍵:field.setAccessible(true) 後 field.get(object) 讀取私有字段值
}
public static <T> T newInstance(Class<T> clazz)
throws ... { return newInstance(clazz, new Class[0], new Object[0]); }
public static <T> T newInstance(Class<T> clazz, Class<?>[] paramTypes, Object[] params)
throws ... { return clazz.getConstructor(paramTypes).newInstance(params); }
用法:Rectangle r = ReflectionUtil.newInstance(Rectangle.class, new Class[]{int.class, int.class, int.class, int.class}, new Object[]{1,2,100,200});
// 遞歸查找字段 (含父類)
public static Field getDeclaredField(Object object, String name)
throws NoSuchFieldException {
Field field = null;
Class<?> clazz = object.getClass();
do {
try { field = clazz.getDeclaredField(name); }
catch (Exception e) {}
} while (field == null && (clazz = clazz.getSuperclass()) != null);
if (field == null) throw new NoSuchFieldException();
return field;
}
public static void setFieldValue(Object object, String fieldName, Object newValue)
throws ... {
Field field = getDeclaredField(object, fieldName);
field.setAccessible(true);
field.set(object, newValue);
}
public static Method getDeclaredMethod(Object object, String name)
throws NoSuchMethodException { ... } // 同字段遞歸查找邏輯
public static Object invokeMethod(Object object, String methodName, Object... args)
throws ... {
Method method = getDeclaredMethod(object, methodName);
method.setAccessible(true);
return method.invoke(object, args);
}
系統中存在 Book、Address、Product 等十幾個領域對象,需實現「任意對象中任意字段包含關鍵字」的全文搜索。傳統方案需每個類實現 Searchable 接口,維護成本極高。
// 獲取類及所有父類的字段 (緩存優化)
public static List<Field> getDeclaredFields(Class clazz) {
List<Field> fields = new ArrayList<>();
do {
fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
} while ((clazz = clazz.getSuperclass()) != null);
return fields;
}
// 通用搜索入口
public static boolean search(Object object, String criteria)
throws IllegalArgumentException, IllegalAccessException {
for (Field field : getDeclaredFields(object.getClass())) {
field.setAccessible(true);
Object value = field.get(object);
if (String.valueOf(value).equalsIgnoreCase(criteria)) {
return true;
}
}
return false;
}
Book book = new Book(); book.setIsbn("123456789-X"); book.setName("Reflection in Action");
Address addr = new Address(); addr.setCity("Valletta");
search(book, "Valletta"); // false
search(addr, "Valletta"); // true
// 新增類型零代碼修改,自動支援
| 維度 | 影響 | 緩解策略 |
|---|---|---|
| 性能 | JIT 無法優化,方法調用慢 10-100 倍 | 緩存 Method/Field 對象;熱點路徑用 MethodHandle/VarHandle |
| 安全 | 破壞封裝,可修改 final/不可變對象 | SecurityManager 限制;代碼審計禁止業務邏輯用反射 |
| 可維護性 | 重構時編譯器無法檢測字符串引用 | 常量定義字段/方法名;單元測試覆蓋反射路徑 |
| 模塊化 | Java 9+ 模塊系統強封裝需 opens 導出 | 模塊描述符配置 opens package to 模塊 |
Map<Class, Field[]> fieldCache = new ConcurrentHashMap<>()NoSuchFieldException、IllegalAccessException、InvocationTargetException<T> T newInstance(Class<T> clazz)反射賦予 Java 動態能力,讓「對象結構」成為可編程數據。通過 ReflectionUtil 封裝底層 API,構建通用搜索、序列化、映射等基礎設施,可大幅減少樣板代碼。但「大權在手,大責在肩」—— 嚴守層級邊界、緩存熱點、防御式編程,方能馭此雙刃劍。