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

Java 深拷貝與淺拷貝詳解:clone()、序列化、性能對比

     編輯:Java 相關知識

一、概念速覽

  • 淺拷貝:基本類型複製值,引用類型複製**地址**。兩對象共享同一引用對象,修改其中一個會影響另一個。
  • 深拷貝:基本類型複製值,引用類型**遞歸新建對象**。兩對象完全獨立,互不干擾。

二、clone() 實現淺/深拷貝

1. 默認 clone() = 淺拷貝

class Body implements Cloneable {
    int height;
    @Override protected Body clone() {
        try { return (Body) super.clone(); }
        catch (CloneNotSupportedException e) { throw new AssertionError(); }
    }
}
class Person implements Cloneable {
    String name; Body body;
    @Override protected Person clone() {
        try { return (Person) super.clone(); } // body 為引用,淺拷貝
        catch (CloneNotSupportedException e) { throw new AssertionError(); }
    }
}
// 測試
Person p1 = new Person("A", new Body(180));
Person p2 = p1.clone();
p2.body.height = 170;
System.out.println(p1.body.height); // 170 → 原對象被修改!

2. 重寫 clone() 實現深拷貝

@Override protected Person clone() {
    Person p = (Person) super.clone();
    p.body = body.clone(); // 關鍵:手動深拷貝引用字段
    return p;
}
// 測試
p2.body.height = 170;
System.out.println(p1.body.height); // 180 → 原對象不變

三、序列化實現深拷貝 (通用、無需逐層實現 Cloneable)

import java.io.*;

public class CloneUtil {
    @SuppressWarnings("unchecked")
    public static  T deepClone(T obj) {
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
             ObjectOutputStream oos = new ObjectOutputStream(bos)) {
            oos.writeObject(obj);
            try (ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
                 ObjectInputStream ois = new ObjectInputStream(bis)) {
                return (T) ois.readObject();
            }
        } catch (IOException | ClassNotFoundException e) {
            throw new RuntimeException("深拷貝失敗", e);
        }
    }
}

// 使用:所有類實現 Serializable
class Teacher implements Serializable { String name; int age; }
class Student implements Serializable { String name; Teacher teacher; }

Teacher t = new Teacher("老王", 40);
Student s1 = new Student("小明", t);
Student s2 = CloneUtil.deepClone(s1);
s2.teacher.name = "老李";
System.out.println(s1.teacher.name); // 老王 → 完全隔離

四、性能對比 (簡單對象 100 萬次)

// 構造器複製 (手寫 new)      : ~30 ms  (最快,推薦簡單對象)
// clone() 遞歸                : ~60 ms
// Apache SerializationUtils   : ~450 ms
// JSON (Jackson) 序列化反序列化: ~800 ms

結論:**構造器/工廠複製最快**,clone() 次之,序列化/JSON 適合複雜對象圖或跨進程傳輸。

五、避坑指南

  • transient 字段序列化會丟失 (為 null/默認值),深拷貝時需注意。
  • 循環引用:clone() 會 StackOverflow,序列化自動處理。
  • 單例/枚舉/線程池等**不應被拷貝**的對象,需在 clone()/readObject() 中返回原實例。
  • 集合深拷貝:new ArrayList<>(list) 只是淺拷貝元素,需流式 list.stream().map(e -> deepClone(e)).collect(...)。

六、最佳實踐總結

  1. **首選不可變對象** (final + 無 setter),消除拷貝需求。
  2. **簡單對象用構造器複製**,代碼清晰、性能最優。
  3. **繼承體系固定、層級淺** 用 clone() 遞歸。
  4. **複雜對象圖、第三方類、跨模塊** 用序列化/JSON/三方庫。
  5. **文檔標註拷貝深度**,避免調用方誤解。

深拷貝是手段,**消除可變共享狀態** 才是目的。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved