首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

Java 深拷貝完整方案:序列化 vs JSON 兩種實現與效能對比

     編輯:Java 程式設計入門

淺拷貝 vs 深拷貝

方案一: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)
*/

選型決策表

類型行為適用場景
淺拷貝複製引用,指向同一對象不可變對象、只讀場景
深拷貝遞歸複製整個對象圖可變對象隔離、快照、撤銷重做

避坑指南

  1. 序列化版本號:显式聲明 serialVersionUID,避免類演進導致反序列化失敗
  2. transient 字段:序列化會跳過,深拷貝後為 null/default
  3. 單例/枚舉:反序列化會創建新實例,破壞單例模式,需實現 readResolve()
  4. JSON 循環引用:Jackson 需 @JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id")
  5. 泛型擦除:JSON 反序列化需 TypeReference/TypeToken 保留泛型資訊
  6. 不可變對象:無需深拷貝,直接共享引用

現代替代方案

  • Record (Java 16+):不可變、自動生成構造器/equals/hashCode/toString,**天然無需深拷貝**
  • Immutable 集合:List.copyOf()、Map.copyOf() (Java 10+)
  • MapStruct:編譯期生成映射代碼,效能接近手寫
  • 持久化資料結構:PCollections、Vavr——共享結構、高效「修改」

總結

深拷貝是雙刃劍:**能解決可變共享問題,但帶來效能與複雜度代價**。首選不可變設計避免深拷貝;必須深拷貝時,**Jackson JSON 為通用首選**,手寫複製為效能首選。理解各方案邊界(循環引用、單例、transient、泛型),才能在生產環境穩健落地。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
場景推薦方案理由
高效能、核心路徑手寫複製 / MapStruct / 避免深拷貝零反射、零序列化開銷
通用工具、原型模式Jackson JSON無需 Serializable、效能尚可、生態成熟
已實現 Serializable、不想加依賴Java 序列化零第三方依賴、JDK 內建
跨進程/網絡傳輸JSON (Jackson/Gson)跨語言、可讀、標準化
第三方類、無法修改JSON無需實現接口
圖結構(循環引用)Java 序列化 / 手寫JSON 需配置 @JsonIdentityInfo 處理循環