淺拷貝:
package algorithm;
import java.util.ArrayList;
public class ShallowCopy implements Cloneable{
private String name;
private ArrayList<String> list = new ArrayList<String>();
public void printName(){
System.out.println(this.name);
}
public void setName(String name) {
this.name = name;
}
public void addListValue(String value){
this.list.add(value);
}
public void printlnList() {
System.out.println(this.list);
}
public ShallowCopy() {
System.out.println("shallow copy test");
}
/**
*
* 淺拷貝是指拷貝對象時僅僅拷貝對象本身(包括對象中的基本變量),
* 而不拷貝對象包含的引用指向的對象。深拷貝不僅拷貝對象本身,
* 而且拷貝對象包含的引用指向的所有對象。
*
*/
@Override
protected ShallowCopy clone() throws CloneNotSupportedException {
return (ShallowCopy) super.clone();
}
public static void main(String[] args) throws CloneNotSupportedException {
ShallowCopy shallow = new ShallowCopy();
shallow.setName("yhx");
shallow.addListValue("Java");
shallow.printName();
shallow.printlnList();
ShallowCopy shallowCopy = shallow.clone(); // 克隆
// 打印出兩個對象的地址
System.out.println(shallow);
System.out.println(shallowCopy);
shallowCopy.addListValue("Python");
shallowCopy.printlnList();
shallowCopy.printName();
shallowCopy.setName("hello");
shallow.printName(); // 輸出 yhx
shallowCopy.printName();
shallow.printlnList(); // // 輸出 Java,Python
/**
* 從結果中我們可以看到
拷貝時候雖然創建了新的對象,但是並沒有調用構造方法
對象中的引用對象並沒有拷貝,引用的地址還是和原對象一致
基本類型或者 String 默認會拷貝
像這種只拷貝了對象本身,而對象中引用數據類型沒有被拷貝的拷貝方式,叫做淺拷貝。
淺拷貝往往存在一定的風險,因爲引用對象的地址拷貝前後一致,所以對象的值很容易被更改,不安全。
*/
}
}
深拷貝:
①:
package algorithm;
import java.util.ArrayList;
public class DeepCopy implements Cloneable{
private String name;
private ArrayList<String> list = new ArrayList<>();
public void printlnName() {
System.out.println(this.name);
}
public void setName(String name) {
this.name = name;
}
public void addListValue(String value) {
this.list.add(value);
}
public void printlnList() {
System.out.println(this.list);
}
public DeepCopy() {
System.out.println("deep copy test");
}
@Override
protected DeepCopy clone() throws CloneNotSupportedException {
DeepCopy clone = (DeepCopy) super.clone();
clone.list = (ArrayList<String>) this.list.clone();
return clone;
}
public static void main(String[] args) throws CloneNotSupportedException {
DeepCopy deep = new DeepCopy();
deep.setName("yhx");
deep.addListValue("Java");
deep.printlnName();
deep.printlnList();
DeepCopy deepCopy = deep.clone(); // 克隆
// 打印出兩個對象的地址
System.out.println(deep);
System.out.println(deepCopy);
deepCopy.printlnList();
deepCopy.addListValue("Python");
deepCopy.printlnList();
deepCopy.printlnName();
deepCopy.setName("hello");
deep.printlnName();
deep.printlnList();
//如果字段上有 final 修飾,就不能實現 clone 方法了,因爲 final 變量不能再次被賦值。
}
}
②串行化深拷貝:
package algorithm;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OptionalDataException;
import java.io.Serializable;
public class DeepCopyBySeriablizable{
//串行化很耗時,在一些框架中,我們便可以感受到,它們往往將對象進行串行化後進行傳遞,耗時較多。
public static void main(String[] args)
throws OptionalDataException, ClassNotFoundException, IOException {
long t1 = System.currentTimeMillis();
Professor2 p = new Professor2("wangwu", 50);
Student2 s1 = new Student2("zhangsan", 18, p);
Student2 s2 = (Student2) s1.deepClone();
s2.p.name = "lisi";
s2.p.age = 30;
System.out.println("name=" + s1.p.name + "," + "age=" + s1.p.age); // 學生1的教授不改變。
System.out.println("name=" + s2.p.name + "," + "age=" + s2.p.age);
long t2 = System.currentTimeMillis();
System.out.println(t2-t1);
}
}
class Professor2 implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
String name;
int age;
Professor2(String name, int age) {
this.name = name;
this.age = age;
}
}
class Student2 implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
String name;// 常量對象。
int age;
Professor2 p;// 學生1和學生2的引用值都是一樣的。
Student2(String name, int age, Professor2 p) {
this.name = name;
this.age = age;
this.p = p;
}
public Object deepClone() throws IOException, OptionalDataException,
ClassNotFoundException {
// 將對象寫到流裏
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream oo = new ObjectOutputStream(bo);
oo.writeObject(this);
// 從流裏讀出來
ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
ObjectInputStream oi = new ObjectInputStream(bi);
return (oi.readObject());
}
}