Monday 15 June 2015

Deep Copy vs Shallow Copy in Java


Chúng ta hãy cùng so sánh sự khác nhau giữa deep copy và shallow copy là những khái niệm ít được chú ý trong các cuốn sách, và bài giảng của nhà trường. Sau đó chúng ta xác định được là khi nào thì sử dụng deep copy hay shallow copy: Giả sử tôi có hai biến: originalObj, và copiedObject.
–          Shallow copy:  biến copied object (không sử dụng toán tử bằng) sẽ copy các giá trị là primitive (ví dụ int, boolean) và String, nhưng các thuộc tính (attribute) trong đó vẫn tham chiếu tới địa chỉ cũ. Vì vậy khi ta thay đổi thuộc tính chứa object trong originalObject thì giá trị của attribute đó trong đối tượng đã copy (copiedObject) cũng sẽ thay đổi theo. Vì vậy đôi khi sẽ xảy ra một số tình huống không mong đợi.
–          Nhưng đối với Deep copy: copy toàn bộ giá trị, và tất cả các member trong object được copy cũng tham chiếu tới địa chỉ khác. Nên khi thay đổi giá trị của attribute là object trong originalObject sẽ không làm thay đổi attribute cùng tên trong copiedObject.
Để implement shallow copy, chúng ta cần override phương thức clone() bằng cách implement Clonable cho class. Đối với deep copy, chúng ta có thể sử dụng objectoutput/inputstream và sử dụng wrapper ByteArrayOutput/InputStream để tang thời gian copy. Xem hình bên dưới để xem mô tả, và demo của shallow & deep copy:
package basic;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
/**
*
@author Chutuanluyen
*
*/
public class ShallowDeepCopy {
public static void main(String[] args) throws CloneNotSupportedException {
Data data = new Data();
data.change(1, “A”);
data.print();// 1
Data data1 = data;
data1.print();// 2
data.change(2, “B”);
data1.print();// 3
System.out.println(“——————-\nShallow Copy”);
Data data2 = data.clone();
System.out.println(“Value of original object before changing:”);
data.print();//4
data.change(3,”C”);
System.out.println(“Value of original object after changed:”);
data.print();//5
System.out.println(“Value of copied object:”);
data2.print();//6
System.out.println(“———————\nDeep Copy”);
//Data now stores 3, C is value
Data data3 = data.clone();
System.out.println(“Value of original object before changing:”);
data.print();//7
data.change(4,”D”);
System.out.println(“Value of original object after changed:”);
data.print();//8
System.out.println(“Value of copied object:”);
data3.print();//9
}
}
class Data implements Cloneable {
static int c = 1;
private int i;// primitive value
private Thing s = new Thing(“Xin chao”);
private String aStr = “”;
public void change(int i, String newN) {
this.i = i;
s.setName(newN);
aStr = newN;
}
public void print() {
System.out.println(“——-:” + (c++) + “:——–“);
System.out.println(“int=” + i);
System.out.println(“object=” + s);
System.out.println(“string=” + aStr);
}
/**
* Shallow copy
*/
public Data clone() throws CloneNotSupportedException {
return (Data) super.clone();
}
public Data deepClone() throws IOException, ClassNotFoundException {
// Use ByteArrayOutput/Input for deep cloning.
// We should use byte array output/input for faster
ObjectOutputStream oos = null;
ObjectInputStream ois = null;
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(this);
ois = new ObjectInputStream(new ByteArrayInputStream(
bos.toByteArray()));
return (Data) ois.readObject();
finally {
                     try {
                           if (oos != null) {
                                  oos.close();
                           }
                     } catch (Exception ignore) {
                     }
                     try {
                           if (ois != null) {
                                  ois.close();
                           }
                     } catch (Exception ignore) {
                     }
                     returnnull;
              }
}
}
class Thing implements Serializable {
/**
*
*/
private static final long serialVersionUID = 6703728080088608170L;
String name;
public Thing(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String toString() {
return name;
}
}
Và đây là kết quả đạt được:
——-:1:——–
int=1
object=A
string=A
——-:2:——–
int=1
object=A
string=A
——-:3:——–
int=2
object=B
string=B
——————-
Shallow Copy
Value of original object before changing:
——-:4:——–
int=2
object=B
string=B
Value of original object after changed:
——-:5:——–
int=3
object=C
string=C
Value of copied object:
——-:6:——–
int=2
object=C
string=B
———————
Deep Copy
Value of original object before changing:
——-:7:——–
int=3
object=C
string=C
Value of original object after changed:
——-:8:——–
int=4
object=D
string=D
Value of copied object:
——-:9:——–
int=3
object=D
string=C

No comments:

Post a Comment