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

Java 深拷貝與淺拷貝完整解析

     編輯:Java 相關知識

Java 物件複製:淺拷貝 vs 深拷貝徹底解析

核心概念定義

  • 淺拷貝:創建新物件,複製原物件屬性值。基本類型複製值,引用類型複製記憶體地址。修改引用指向的物件會影響彼此。
  • 深拷貝:不僅複製非引用成員,還為引用類型成員創建新實例並初始化,完全獨立。

驗證:普通賦值屬於淺拷貝

public class Copy {
    public String name;
    public int age;
    public Copy(String name, int age) { this.name = name; this.age = age; }
}

public class Test {
    public static void main(String[] args) {
        Copy first = new Copy("hzw", 24);
        Copy second = first; // 引用賦值
        second.name = "shanxi";
        System.out.println(first.name); // 輸出 shanxi - 受影響!
    }
}

驗證:clone() 預設也是淺拷貝

class Copy implements Cloneable {
    public String name;
    public int age;
    public Student student; // 引用類型
    // 建構子、getter/setter 省略
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone(); // 預設淺拷貝
    }
}

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student stu = new Student(95);
        Copy first = new Copy("hzw", 24, stu);
        Copy second = (Copy) first.clone();

        second.name = "shanxi";
        second.student.score = 60;

        System.out.println(first == second); // false - 物件不同
        System.out.println(first.student == second.student); // true - 同一 Student 實例!
        System.out.println(first.student.score); // 60 - 被修改!
    }
}

實作深拷貝方案一:遞歸重寫 clone()

必須讓所有引用類型成員類別實作 Cloneable 並重寫 clone(),層層調用:

class Copy implements Cloneable {
    // ...
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Copy copy = (Copy) super.clone();
        copy.student = (Student) student.clone(); // 深拷貝引用成員
        return copy;
    }
}

class Student implements Cloneable {
    public int score;
    // ...
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

缺點:引用鏈長時極其繁瑣,需修改所有相關類別。

實作深拷貝方案二:序列化與反序列化(推薦)

所有相關類別實作 Serializable,透過序列化/反序列化自動實現深拷貝,無需逐層實作 clone:

class Copy implements Serializable {
    public String name;
    public int age;
    public Student student;
    // 建構子省略
}

class Student implements Serializable {
    public int score;
    public College school;
    // 建構子省略
}

class College implements Serializable {
    public String schoolName;
    // 建構子省略
}

public class Test {
    public static void main(String[] args) throws Exception {
        College school = new College("nongda");
        Student student = new Student(95, school);
        Copy copy = new Copy("hzw", 23, student);

        // 序列化
        FileOutputStream fos = new FileOutputStream("copy.txt");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(copy);
        oos.close();

        // 反序列化
        FileInputStream fis = new FileInputStream("copy.txt");
        ObjectInputStream ois = new ObjectInputStream(fis);
        Copy another = (Copy) ois.readObject();
        ois.close();

        // 驗證完全獨立
        System.out.println(copy == another); // false
        System.out.println(copy.student == another.student); // false
        System.out.println(copy.student.school == another.student.school); // false

        another.student.school.schoolName = "wuda";
        System.out.println(copy.student.school.schoolName); // nongda - 未受影響!
    }
}

總結比較

方式實作複雜度效能適用場景
重寫 clone() 遞歸高(需修改所有類別)較好簡單物件圖、效能敏感
序列化/反序列化低(只需實作 Serializable)較差(I/O 開銷)複雜物件圖、通用性要求高

建議:簡單場景用 clone 遞歸,複雜物件圖優先考慮序列化方案,或使用第三方庫(如 Apache Commons Lang SerializationUtils.clone())。

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