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

Java 深層複製與淺層複製完整解析與實作範例

     編輯:Java 程式設計入門

核心概念區別

  • 淺層複製:僅複製物件本身及其基本型別欄位;引用型別欄位仍指向原物件,修改副本的引用欄位會影響原物件。
  • 深層複製:遞迴複製物件及其所有引用型別欄位所指向的物件,副本與原物件完全獨立,互不干擾。

實作方案

1. 深層複製:序列化反序列化法

利用 Java 序列化機制,將物件寫入位元組流再讀出,實現完全獨立的深層複製。要求物件及其所有引用欄位實作 Serializable 介面。

import java.io.*;

public class DepthClone {
    public final static Object objectCopy(Object oldObj) {
        Object newObj = null;
        try {
            ByteArrayOutputStream bo = new ByteArrayOutputStream();
            ObjectOutputStream oo = new ObjectOutputStream(bo);
            oo.writeObject(oldObj);

            ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
            ObjectInputStream oi = new ObjectInputStream(bi);
            newObj = oi.readObject();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        return newObj;
    }
}

2. 淺層複製:實作 Cloneable + 覆寫 clone()

import java.io.Serializable;

public class SimpleClone implements Cloneable, Serializable {
    private static final long serialVersionUID = -7552721152118950502L;

    public String s = null;
    public Object o = null;
    public CloneObject cloneObject = null;

    public SimpleClone(CloneObject cloneObject) {
        this.cloneObject = cloneObject;
    }

    @Override
    public Object clone() {
        SimpleClone newSimpleClone = null;
        try {
            newSimpleClone = (SimpleClone) super.clone(); // 淺層複製
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return newSimpleClone;
    }
}

3. 被複製的引用物件


public class CloneObject implements Serializable {
    private static final long serialVersionUID = 4332788486669750696L;
    private String name;

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

驗證測試


public class TestClone {
    public static void main(String[] arg) {
        CloneObject obj1 = new CloneObject();
        obj1.setName("cloneOne");
        CloneObject obj2 = new CloneObject();
        obj2.setName("cloneTwo");

        SimpleClone simpleClone1 = new SimpleClone(obj1);
        SimpleClone simpleClone2 = new SimpleClone(obj2);

        simpleClone1.s = "simpleClone1";
        simpleClone1.o = "simpleClone1Object";

        // 使用深層複製
        simpleClone2 = (SimpleClone) DepthClone.objectCopy(simpleClone1);

        // 修改副本的引用物件屬性
        simpleClone2.cloneObject.setName("cloneThree");

        System.out.println(simpleClone1.cloneObject.getName()); // 輸出 cloneOne,未受影響
        System.out.println(simpleClone2.cloneObject.getName()); // 輸出 cloneThree
    }
}

結果分析

  • 深層複製:simpleClone1.cloneObject 仍為 "cloneOne",simpleClone2.cloneObject 為 "cloneThree",兩者完全獨立。
  • 若改用淺層複製(simpleClone1.clone()),兩者共用同一 CloneObject,修改副本會導致原物件同步變更。

其他深層複製替代方案

  • 手動遞迴複製:在 clone() 中逐欄位 new 新物件,效能最佳但程式碼繁瑣。
  • 第三方庫:Apache Commons Lang SerializationUtils.clone()、Gson/Jackson JSON 序列化、Kryo、MapStruct 等。
  • 建構式複製:提供複製建構子 public Foo(Foo other) 手動深層複製各欄位。

選型建議

場景推薦方案
簡單物件圖、效能敏感手動複製或複製建構子
複雜物件圖、含第三方類別、原始碼不可改序列化法或第三方庫(Kryo 最快)
Web 專案常見 DTO/VO 轉換MapStruct 編譯期生成、或 JSON 序列化
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved