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 - 受影響!
}
}
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 - 被修改!
}
}
必須讓所有引用類型成員類別實作 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())。