基本概念
淺拷貝:複製後對象的所有基本類型域的值與原對象相等,所有引用指向的對象和原對象指向的對象相同
深拷貝:複製後對象的所有基本類型的值與原對象相等,且其引用鏈上的所有對象都獲得了一份拷貝
依賴clone方法的深度拷貝
在Java的Object類中有一個clone方法,該方法的行爲由Cloneable接口決定,當某個類實現了Cloneable接口時,Object的clone就返回該對象的逐域拷貝(淺拷貝),否則就會拋出CloneNotSupportedException異常。由於Object類的clone方法的訪問權限爲protected,當一個類實現Cloneable接口時,它不一定具有可訪問的clone方法。爲了使該類型具有適當的、表現良好的clone方法,需要滿足以下幾個條件:
- 定義一個訪問權限爲public的clone方法
- 在該clone方法中調用super.clone() //要求父類的clone表現良好
- 該類實現Cloneable接口
良好的clone方法通常需要滿足以下約定:
- x.clone() != x
- x.clone().getClass() == x.getClass()
- x.clone().equals(x) == true
class Professor implements Cloneable {
String name;
int age;
public Professor(String name, int age){
this.name = name;
this.age = age;
}
@Override
public Professor clone() throws CloneNotSupportedException {
return (Professor)super.clone();
}
}
public class Student implements Cloneable {
String name;
int age;
Professor p;
public Student(String name, int age, Professor p){
this.name = name;
this.age = age;
this.p = p;
}
@Override
public Student clone() throws CloneNotSupportedException {
Student s = (Student)super.clone();
s.p = this.p.clone();
return s;
}
public static void main(String[] args) throws CloneNotSupportedException{
Professor p = new Professor("ShunZhongShan", 56);
Student s = new Student("JiangJieShi", 20, p);
Student s1 = s.clone();
System.out.println("Student: name = " + s1.name + " ; age = " + s1.age + "\nProfessor: name = " + s1.p.name + " ; age = " + s1.p.age);
}
}
運行結果:Student: name = JiangJieShi ; age = 20
Professor: name = ShunZhongShan ; age = 56
依賴序列化的深度拷貝
另一種實現深度拷貝的方式就是使用序列化,序列化的過程是將對象轉換成數據流;反序列化的過程解析數據流並創建一個新的對象。示例代碼如下:
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
class Professor implements Serializable {
private static final long serialVersionUID = 252398134512833273L;
String name;
int age;
public Professor(String name, int age){
this.name = name;
this.age = age;
}
}
public class Student implements Serializable {
private static final long serialVersionUID = 4299622782948980557L;
String name;
int age;
Professor p;
public Student(String name, int age, Professor p){
this.name = name;
this.age = age;
this.p = p;
}
public Object deepClone() throws IOException, ClassNotFoundException{
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(bo);
os.writeObject(this);
ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
ObjectInputStream is = new ObjectInputStream(bi);
return is.readObject();
}
public static void main(String[] args) throws ClassNotFoundException, IOException{
Professor p = new Professor("ShunZhongShan", 56);
Student s = new Student("JiangJieShi", 20, p);
Student s1 = (Student)s.deepClone();
System.out.println("Student: name = " + s1.name + " ; age = " + s1.age + "\nProfessor: name = " + s1.p.name + " ; age = " + s1.p.age);
}
}
運行結果爲:Student: name = JiangJieShi ; age = 20
Professor: name = ShunZhongShan ; age = 5