專案需導出 CSV,但 List 中物件型別不固定,無法硬編碼 getter。利用反射可動態獲取任意物件的所有欄位值。
package com.hb.test;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) throws Exception {
Person p1 = new Person("111", "aaa");
Person p2 = new Person("222", "bbb");
List<Object> list = new ArrayList<>();
list.add(p1);
list.add(p2);
exportCsv(list);
}
public static void exportCsv(List<Object> list) throws Exception {
for (Object obj : list) {
Field[] fields = obj.getClass().getDeclaredFields();
for (Field field : fields) {
if (!field.isAccessible()) {
field.setAccessible(true); // 破壞私有封裝
}
Object value = field.get(obj);
System.out.print(value + "\t");
}
System.out.println();
}
}
}
class Person {
private String id;
private String name;
public Person(String id, String name) {
this.id = id;
this.name = name;
}
}
getDeclaredFields():取得類別宣告的所有欄位(含 private),不含繼承欄位。setAccessible(true):繞過 Java 存取控制,讀取私有欄位。field.get(obj):從具體物件實例獲取欄位值。public static <T> void writeCsv(List<T> data, Writer writer) throws Exception {
if (data.isEmpty()) return;
Field[] fields = data.get(0).getClass().getDeclaredFields();
// 寫表頭
for (int i = 0; i < fields.length; i++) {
if (i > 0) writer.write(",");
writer.write(fields[i].getName());
}
writer.write("\n");
// 寫資料
for (T obj : data) {
for (int i = 0; i < fields.length; i++) {
if (i > 0) writer.write(",");
fields[i].setAccessible(true);
Object val = fields[i].get(obj);
writer.write(val != null ? val.toString() : "");
}
writer.write("\n");
}
}