物件持久化與網路傳輸是 Java 開發核心場景。本文對比 JDK 內建序列化與 Jackson JSON 序列化,提供可直接運行的完整範例,幫助你根據效能、相容性、可讀性選擇最適方案。
Serializable 介面(標記介面,無方法)。ObjectOutputStream / ObjectInputStream 進行寫入與讀取。// 序列化
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("data.bin"))) {
out.writeObject(myObject);
}
// 反序列化
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("data.bin"))) {
MyClass obj = (MyClass) in.readObject();
}
InvalidClassException。@JsonIgnore、@JsonProperty、@JsonFormat)靈活控制輸出。ObjectMapper mapper = new ObjectMapper();
// 序列化為檔案
mapper.writeValue(new File("data.json"), myObject);
// 序列化為字串
String json = mapper.writeValueAsString(myObject);
// 反序列化
MyClass obj = mapper.readValue(new File("data.json"), MyClass.class);
MyClass obj2 = mapper.readValue(jsonString, MyClass.class);
mapper.configure(SerializationFeature.INDENT_OUTPUT, true); // 美化輸出
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); // 忽略未知欄位
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); // 日期格式
以下整合兩種序列化方式,展示靜態欄位、集合、自訂 toString 的處理差異。
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.*;
import java.util.ArrayList;
public class Zoo implements Serializable {
private static final long serialVersionUID = 1L;
private static final ObjectMapper MAPPER = new ObjectMapper();
public static int maxAnimalCount;
public ArrayList animals = new ArrayList<>();
public void addAnimal(String name) {
if (animals.size() < maxAnimalCount) animals.add(name);
}
// --- JDK 序列化 ---
public void serializeToLog(String path) {
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(path))) {
out.writeObject(this);
} catch (IOException e) { e.printStackTrace(); }
}
public static Zoo deserializeFromLog(String path) {
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(path))) {
return (Zoo) in.readObject();
} catch (Exception e) { e.printStackTrace(); return null; }
}
// --- Jackson JSON 序列化 ---
public void serializeJSONToLog(String path) {
try { MAPPER.writeValue(new File(path), this); }
catch (IOException e) { e.printStackTrace(); }
}
public static Zoo deserializeJSONFromLog(String path) {
try { return MAPPER.readValue(new File(path), Zoo.class); }
catch (IOException e) { e.printStackTrace(); return null; }
}
@Override public String toString() {
return "Zoo{animals=" + animals + ", max=" + maxAnimalCount + "}";
}
// --- 測試主程式 ---
public static void main(String[] args) {
Zoo zoo1 = new Zoo(); Zoo.setMax(100);
zoo1.addAnimal("hamster"); zoo1.addAnimal("sheep");
zoo1.serializeToLog("zoo1.bin");
zoo1.serializeJSONToLog("zoo1.json");
Zoo zoo2 = Zoo.deserializeFromLog("zoo1.bin");
Zoo zoo3 = Zoo.deserializeJSONFromLog("zoo1.json");
System.out.println("JDK 反序列化: " + zoo2);
System.out.println("JSON 反序列化: " + zoo3);
}
}
| 維度 | JDK 序列化 | Jackson JSON |
|---|---|---|
| 資料格式 | 二進制 | UTF-8 文本 |
| 跨語言支援 | 極差 | 極佳 |
| 可讀性/除錯 | 不可讀 | 人類可讀 |
| 效能(大物件) | 較快 | 略慢(可用流式優化) |
| 版本演進 | 脆弱(需 serialVersionUID) | 彈性(忽略未知欄位) |
| 安全性 | 高風險(反序列化漏洞) | 低風險(無程式碼執行) |
| 適用場景 | JVM 內部 RPC、暫存 | REST API、設定檔、日誌、跨系統 |
Serializable,對外 DTO 使用 Jackson 註解控制。ObjectInputFilter (Java 9+) 白名單機制。