Reflect 應用
從 Class 獲取資訊
Class 物件表示所載入的類別,取得Class物件之後,你就可以取得與類別相關聯的資訊,像是套件(package)(別忘了package也是類別名稱的一部 份)、建構方法、方法成員、資料成員等的訊息,而每一個訊息,也會有相應的類別型態,例如套件的對應型態是java.lang.Package,建構方法的對應型態是java.lang.reflect.Constructor,方法成員的對應型態是java.lang.reflect.Method,資料成員的對應型態是java.lang.reflect.Field等。
來看個簡單的示範,以下可以讓您取得所指定類別上的套件名稱:
try {
Class c = Class.forName(args[0]);
Package p = c.getPackage();
System.out.println(p.getName());
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("沒有指定類別");
} catch (ClassNotFoundException e) {
System.out.println("找不到指定類別");
}你可以分別取回Field、Constructor、Method等物件,分別代表資料成員、建構方法與方法成員,以下範例簡單地實作了取得類別基本資訊的程式:
try {
Class c = Class.forName(args[0]);
// 取得套件代表物件
Package p = c.getPackage();
System.out.printf("package %s;%n", p.getName());
// 取得型態修飾,像是class、interface
int m = c.getModifiers();
System.out.print(Modifier.toString(m) + " ");
// 如果是介面
if (Modifier.isInterface(m)) {
System.out.print("interface ");
} else {
System.out.print("class ");
}
System.out.println(c.getName() + " {");
// 取得宣告的資料成員代表物件
Field[] fields = c.getDeclaredFields();
for (Field field : fields) {
// 顯示權限修飾,像是public、protected、private
System.out.print("\t" + Modifier.toString(field.getModifiers()));
// 顯示型態名稱
System.out.print(" " + field.getType().getName() + " ");
// 顯示資料成員名稱
System.out.println(field.getName() + ";");
}
// 取得宣告的建構方法代表物件
Constructor[] constructors = c.getDeclaredConstructors();
for (Constructor constructor : constructors) {
// 顯示權限修飾,像是public、protected、private
System.out.print("\t" + Modifier.toString(constructor.getModifiers()));
// 顯示建構方法名稱
System.out.println(" " + constructor.getName() + "();");
}
// 取得宣告的方法成員代表物件
Method[] methods = c.getDeclaredMethods();
for (Method method : methods) {
// 顯示權限修飾,像是public、protected、private
System.out.print("\t" + Modifier.toString(method.getModifiers()));
// 顯示返回值型態名稱
System.out.print(" " + method.getReturnType().getName() + " ");
// 顯示方法名稱
System.out.println(method.getName() + "();");
}
System.out.println("}");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("沒有指定類別");
} catch (ClassNotFoundException e) {
System.out.println("找不到指定類別");
}亦可呼叫物件內方法
看看以下範例以最簡單的Get/Set方法
進階應用 - auto get/set value
實戰案例
需求內容:
輸出前後資料比對結果
轉換變數名稱,改為可閱讀內容 Ex. status -> 狀態
可轉換變數資料結果 Ex. 1:啟用, 0: 停用 -> status:1 -> 狀態:啟用
排序固定,方便查看比對內容
廢話不多,先看結果。
從結果範例可以看到,這種結果通常會應用到後台使用者操作日誌,以及需要紀錄前後結果對照的功能上,以便釐清前後關係。
以下是針對這五個方法的簡單說明:
getAllFields(Class<?> clazz): 這個方法用於獲取一個類及其超類中的所有字段,並根據特定的條件(通過FieldInfo注解)進行篩選。如果類不是 CGLIB 代理類,則優先從fieldsMap中獲取,否則調用_getAllFields方法獲取並存入緩存中。_getAllFields(Class<?> clazz): 這個私有方法實際上執行字段的提取工作。它首先獲取指定類的所有宣告字段,然後通過excludeField方法進行篩選,接著繼續處理超類的字段,直到所有字段被提取並返回。excludeField(List<Field> fieldList): 這個方法是_getAllFields中使用的輔助方法,它通過過濾字段列表,只保留標有FieldInfo注解且允許包含(通過include()方法)的字段。extract(Object obj): 這個方法從給定的對象中提取字段信息並創建一個映射,其中包含字段名稱和值。它使用BeanUtils.getAllFields獲取所有字段,然後使用反射獲取字段的值。如果該字段允許空值,或者字段值不為空,則將字段信息添加到映射中。compare(Object from, Object to, String... ignoreFields): 這個方法用於比較兩個對象的字段變更。它使用extract方法提取兩個對象的字段信息,然後對比這些信息,找到不同的字段。忽略指定的字段(如果有的話),最終返回一個映射,其中包含變更的字段名稱和相關信息。transExternalName(ConvertExternalNameWrapper convertWrapper): 這個方法接受一個ConvertExternalNameWrapper對象,該對象包含比較結果的映射,將這些比較結果轉換為外部名稱的形式,並返回一個更新後的ConvertExternalNameWrapper對象。在這個方法中,首先創建了兩個空的映射fromMap和toMap用於存儲轉換後的數據。
這五個方法一起提供了一個工具集,用於處理對象的字段操作、篩選和比較。它們基於反射和 Java 的反射 API,讓你可以更便捷地操作和分析對象的字段數據。
Last updated