So Sánh Shallow Copy và Deep Copy trong Java và Python
Khi làm việc với các đối tượng trong Java hoặc Python, một trong những khái niệm khó khăn nhất là sự khác biệt giữa shallow copy và deep copy. Cả hai ngôn ngữ đều truyền tham chiếu đến các đối tượng, điều này có nghĩa là nếu bạn không cẩn thận, các "bản sao" của bạn có thể không độc lập như bạn nghĩ.
Trong bài viết này, chúng ta sẽ phân tích sự khác biệt với ví dụ rõ ràng trong Java và Python.
🔹 Shallow Copy là gì?
Một shallow copy tạo ra một đối tượng mới, nhưng chỉ sao chép cấu trúc cấp cao. Nếu đối tượng chứa các đối tượng khác (danh sách, bản đồ, đối tượng tùy chỉnh), những đối tượng này không được nhân bản — cả hai bản sao vẫn trỏ đến những đối tượng lồng nhau giống nhau.
👉 Việc thay đổi một đối tượng lồng nhau trong một bản sao sẽ ảnh hưởng đến bản sao còn lại.
✅ Shallow Copy trong Java
Dưới đây là ví dụ về shallow copy trong Java:
java
import java.util.*;
class Person implements Cloneable {
String name;
List<String> hobbies;
Person(String name, List<String> hobbies) {
this.name = name;
this.hobbies = hobbies;
}
// Shallow copy
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Main {
public static void main(String[] args) throws CloneNotSupportedException {
List<String> hobbies = new ArrayList<>(Arrays.asList("Cricket", "Chess"));
Person p1 = new Person("John", hobbies);
Person p2 = (Person) p1.clone(); // shallow copy
p2.hobbies.add("Football");
System.out.println("p1 hobbies: " + p1.hobbies);
System.out.println("p2 hobbies: " + p2.hobbies);
}
}
Kết quả:
p1 hobbies: [Cricket, Chess, Football]
p2 hobbies: [Cricket, Chess, Football]
Cả hai đối tượng chia sẻ cùng một tham chiếu danh sách.
✅ Shallow Copy trong Python
Dưới đây là ví dụ về shallow copy trong Python:
python
import copy
p1 = {"name": "John", "hobbies": ["Cricket", "Chess"]}
p2 = copy.copy(p1) # shallow copy
p2["hobbies"].append("Football")
print("p1 hobbies:", p1["hobbies"])
print("p2 hobbies:", p2["hobbies"])
Kết quả:
p1 hobbies: ['Cricket', 'Chess', 'Football']
p2 hobbies: ['Cricket', 'Chess', 'Football']
Hành vi tương tự như Java — shallow copy vẫn chia sẻ danh sách bên trong.
🔹 Deep Copy là gì?
Một deep copy sao chép không chỉ đối tượng mà còn tất cả các đối tượng mà nó tham chiếu. Bản sao là hoàn toàn độc lập — việc thay đổi một không ảnh hưởng đến cái còn lại.
✅ Deep Copy trong Java
Dưới đây là ví dụ về deep copy trong Java:
java
import java.util.*;
class Person implements Cloneable {
String name;
List<String> hobbies;
Person(String name, List<String> hobbies) {
this.name = name;
this.hobbies = hobbies;
}
// Deep copy
@Override
protected Object clone() throws CloneNotSupportedException {
Person cloned = (Person) super.clone();
cloned.hobbies = new ArrayList<>(this.hobbies); // sao chép danh sách riêng biệt
return cloned;
}
}
public class Main {
public static void main(String[] args) throws CloneNotSupportedException {
List<String> hobbies = new ArrayList<>(Arrays.asList("Cricket", "Chess"));
Person p1 = new Person("John", hobbies);
Person p2 = (Person) p1.clone(); // deep copy
p2.hobbies.add("Football");
System.out.println("p1 hobbies: " + p1.hobbies);
System.out.println("p2 hobbies: " + p2.hobbies);
}
}
Kết quả:
p1 hobbies: [Cricket, Chess]
p2 hobbies: [Cricket, Chess, Football]
Bây giờ các danh sách là độc lập.
✅ Deep Copy trong Python
Dưới đây là ví dụ về deep copy trong Python:
python
import copy
p1 = {"name": "John", "hobbies": ["Cricket", "Chess"]}
p2 = copy.deepcopy(p1) # deep copy
p2["hobbies"].append("Football")
print("p1 hobbies:", p1["hobbies"])
print("p2 hobbies:", p2["hobbies"])
Kết quả:
p1 hobbies: ['Cricket', 'Chess']
p2 hobbies: ['Cricket', 'Chess', 'Football']
Ở đây cũng vậy, danh sách bên trong được sao chép độc lập.
🔹 So sánh Nhanh Shallow Copy và Deep Copy
| Tính năng | Shallow Copy 🟡 | Deep Copy 🟢 |
|---|---|---|
| Sao chép đối tượng chính? | ✅ Có | ✅ Có |
| Sao chép đối tượng lồng nhau? | ❌ Không (chung) | ✅ Có |
| Thay đổi đối tượng lồng nhau ảnh hưởng đến gốc? | ✅ Có | ❌ Không |
| Ví dụ trong Java | super.clone() |
new ArrayList<>(field) |
| Ví dụ trong Python | copy.copy() |
copy.deepcopy() |
🔹 Phân Tích Thực Tế
- Shallow Copy: Bạn photocopy một báo cáo, nhưng cả hai bản sao đều tham chiếu đến cùng một tệp phụ lục ngoài. Nếu ai đó chỉnh sửa phụ lục, cả hai báo cáo đều bị ảnh hưởng.
- Deep Copy: Bạn photocopy báo cáo và cũng nhân bản phụ lục. Mỗi báo cáo là hoàn toàn độc lập.
🔹 Những Điều Cần Lưu Ý
- Trong Java,
super.clone()→ shallow copy; bạn phải nhân bản các trường có thể thay đổi bằng tay cho deep copy. - Trong Python,
copy.copy()→ shallow copy;copy.deepcopy()→ deep copy. - Nếu đối tượng của bạn chỉ chứa dữ liệu không thay đổi (như số nguyên, chuỗi), shallow copy thường là đủ.
- Nếu đối tượng của bạn chứa các cấu trúc dữ liệu có thể thay đổi (danh sách, dict, bản đồ), bạn thường muốn một deep copy.
🔹 Câu Hỏi Thường Gặp
Shallow Copy có an toàn không?
Shallow copy không an toàn khi bạn cần độc lập giữa các đối tượng, vì thay đổi ở bản sao này có thể ảnh hưởng đến bản sao khác.
Làm thế nào để kiểm tra một đối tượng có phải là bản sao sâu hay không?
Bạn có thể kiểm tra xem các thuộc tính của đối tượng có tham chiếu đến cùng một đối tượng hay không, điều này cho thấy đó là shallow copy.
Bài viết này giúp bạn hiểu sâu về sự khác biệt giữa shallow copy và deep copy, từ đó áp dụng chính xác trong lập trình Java và Python.