| 類型 | 行為 | 適用場景 |
| 淺拷貝 | 複製引用,指向同一對象 | 不可變對象、只讀場景 |
| 深拷貝 | 遞歸複製整個對象圖 | 可變對象隔離、快照、撤銷重做 |
方案一:Java 序列化深拷貝
前置條件
- 所有涉及類實現
Serializable
- 靜態/transient 字段不複製
- 無參構造器(反序列化需要)
通用工具類
public final class SerializationUtils {
private SerializationUtils() {}
@SuppressWarnings("unchecked")
public static T deepCopy(T object) {
if (object == null) return null;
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos)) {
oos.writeObject(object);
try (ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais)) {
return (T) ois.readObject();
}
} catch (IOException | ClassNotFoundException e) {
throw new IllegalArgumentException("深拷貝失敗: " + object.getClass(), e);
}
}
}
方案二:JSON 序列化深拷貝
優勢
- 無需實現 Serializable
- 可處理第三方庫類、無法修改的類
- 人類可讀、便於調試
- 跨語言相容
基於 Jackson 實現(推薦)
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version>
</dependency>
public final class JsonUtils {
private static final ObjectMapper MAPPER = new ObjectMapper();
private JsonUtils() {}
public static T deepCopy(T object, Class clazz) {
if (object == null) return null;
try {
String json = MAPPER.writeValueAsString(object);
return MAPPER.readValue(json, clazz);
} catch (JsonProcessingException e) {
throw new IllegalArgumentException("JSON 深拷貝失敗", e);
}
}
// TypeReference 版本(支援泛型)
public static T deepCopy(T object, TypeReference typeRef) {
if (object == null) return null;
try {
String json = MAPPER.writeValueAsString(object);
return MAPPER.readValue(json, typeRef);
} catch (JsonProcessingException e) {
throw new IllegalArgumentException("JSON 深拷貝失敗", e);
}
}
}
基於 Gson 實現(輕量)
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
public final class GsonUtils {
private static final Gson GSON = new Gson();
public static T deepCopy(T object, Class clazz) {
if (object == null) return null;
String json = GSON.toJson(object);
return GSON.fromJson(json, clazz);
}
public static T deepCopy(T object, TypeToken typeToken) {
if (object == null) return null;
String json = GSON.toJson(object);
return GSON.fromJson(json, typeToken.getType());
}
}
效能對比測試
@State(Scope.Thread)
public class DeepCopyBenchmark {
private ComplexObject source;
@Setup
public void setup() {
source = new ComplexObject(/* 複雜嵌套結構,含 List、Map、自定義對象 */);
}
@Benchmark
public ComplexObject serializationCopy() {
return SerializationUtils.deepCopy(source);
}
@Benchmark
public ComplexObject jacksonCopy() {
return JsonUtils.deepCopy(source, ComplexObject.class);
}
@Benchmark
public ComplexObject gsonCopy() {
return GsonUtils.deepCopy(source, ComplexObject.class);
}
@Benchmark
public ComplexObject manualCopy() {
return source.manualDeepCopy(); // 手寫複製(基準線)
}
}
/*
典型結果(10000 次迭代,複雜對象圖 ~500 節點):
manualCopy: 0.05 ms/op (基準)
serializationCopy: 2.5 ms/op (50x slower)
jacksonCopy: 0.8 ms/op (16x slower)
gsonCopy: 1.2 ms/op (24x slower)
*/
選型決策表
| 場景 | 推薦方案 | 理由 |
| 高效能、核心路徑 | 手寫複製 / MapStruct / 避免深拷貝 | 零反射、零序列化開銷 |
| 通用工具、原型模式 | Jackson JSON | 無需 Serializable、效能尚可、生態成熟 |
| 已實現 Serializable、不想加依賴 | Java 序列化 | 零第三方依賴、JDK 內建 |
| 跨進程/網絡傳輸 | JSON (Jackson/Gson) | 跨語言、可讀、標準化 |
| 第三方類、無法修改 | JSON | 無需實現接口 |
| 圖結構(循環引用) | Java 序列化 / 手寫 | JSON 需配置 @JsonIdentityInfo 處理循環 |
避坑指南
- 序列化版本號:显式聲明
serialVersionUID,避免類演進導致反序列化失敗
- transient 字段:序列化會跳過,深拷貝後為 null/default
- 單例/枚舉:反序列化會創建新實例,破壞單例模式,需實現
readResolve()
- JSON 循環引用:Jackson 需
@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id")
- 泛型擦除:JSON 反序列化需 TypeReference/TypeToken 保留泛型資訊
- 不可變對象:無需深拷貝,直接共享引用
現代替代方案
- Record (Java 16+):不可變、自動生成構造器/equals/hashCode/toString,**天然無需深拷貝**
- Immutable 集合:
List.copyOf()、Map.copyOf() (Java 10+)
- MapStruct:編譯期生成映射代碼,效能接近手寫
- 持久化資料結構:PCollections、Vavr——共享結構、高效「修改」
總結
深拷貝是雙刃劍:**能解決可變共享問題,但帶來效能與複雜度代價**。首選不可變設計避免深拷貝;必須深拷貝時,**Jackson JSON 為通用首選**,手寫複製為效能首選。理解各方案邊界(循環引用、單例、transient、泛型),才能在生產環境穩健落地。
- 上一篇文章: Java toString() 方法深度解析:契約、實現模式、效能影響與最佳實踐
- 下一篇文章: MyBatis 在 CS 架構應用實戰:XML 加密、動態 SqlSessionFactory、多環境隔離
Copyright ©
程式碼之家 All Rights Reserved