先看代码,从结果中分析和总结深拷贝和浅拷贝的区别和实质。
publicclass Father {
public String name;
public int age;
public Father(String name,int age){
this.name=name;
this.age=age;
}
}
public class Person implements Cloneable{
public String name;
private int age;
public Father father;
public Person(String name,int age,Father father){
this.name=name;
this.age=age;
this.father=father;
}
@Override
protected Object clone(){
Person p=null;
try {
p=(Person)super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return p;
}
@Override
public String toString() {
return"Person [name=" +name + ", age=" +age +", fatherName=" +father.name+",fatherAge="+father.age
+ "]";
}
}
客户端程序如下:
publicstaticvoid main(String[] args) {
Person person1 = new Person("son",14,new Father("father", 52));
Person person2=person1;
System.out.println(person1==person2);//指向同一个对象
Person person3=(Person) person1.clone();
System.out.println(person1==person3);
person3.father.name="wangwu";
System.out.println(person1.father.name);
}
打印结果是:
true
false
Wangwu
我们可以看出person1和person2是指向同一个对象而person1和person3指向不同的对象,通过修改person3的futher的name值person1的也改变了,也就是说person1和person3中futher成员变量指向同一个地址,这时候我们就说这种拷贝是浅拷贝。
修改一下程序将Futher类也实现Cloneable接口
publicclass Father implements Cloneable{
public String name;
public int age;
public Father(String name,int age){
this.name=name;
this.age=age;
}
@Override
public Object clone()throws CloneNotSupportedException {
return super.clone();
}
}
Person类的代码也作稍微的修改
public class Person implements Cloneable{
public String name;
private int age;
public Father father;
public Person(String name,int age,Father futher){
this.name=name;
this.age=age;
this.father=father;
}
@Override
protected Object clone(){
Person p=null;
try {
p=(Person)super.clone();
p.futher=(Father)father.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return p;
}
@Override
public String toString() {
return"Person [name=" +name + ", age=" +age +", fatherName=" +father.name+",fatherAge="+father.age
+ "]";
}
}
这样打印的结果是:
true
false
Father
这种拷贝是深拷贝。
浅拷贝是指拷贝对象时仅仅拷贝对象本身(对象中的基本数据类型),而不拷贝对象中包含的引用数据类型,拷贝过后引用数据类型指向被拷贝对象中引用数据类型变量的地址。深拷贝不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象。
深拷贝代码可以这样写:
public Object clone()throws CloneNotSupportedException {
Person p=new Person();
p.age=this.age;
p.name=this.name;
p.father=new Futher(father.name,father.age);
returnp;
}
对于拷贝可能我们比较常用的方式是将对象序列化,序列化拷贝对象的缺点是效率比较低。
修改代码如下:
public class Father implements Serializable{
private static final longserialVersionUID = 1L;
public String name;
public int age;
public Father(String name,int age){
this.name=name;
this.age=age;
}
}
public class Person implements Serializable{
private static final long serialVersionUID = 1L;
public String name;
private int age;
public Father father;
public Person(String name,int age,Father father){
this.name=name;
this.age=age;
this.father=father;
}
public Object deepCopy()throws IOException,ClassNotFoundException{
//写对象到流中
ByteArrayOutputStream os = new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(os);
oos.writeObject(this);
//流中读取对象
ObjectInputStream ois=new ObjectInputStream(newByteArrayInputStream(os.toByteArray()));
Object readObject = ois.readObject();
return readObject;
}
@Override
public String toString() {
return"Person [name=" +name + ", age=" +age +", fatherName=" +father.name+",fatherAge="+father.age
+ "]";
}
}
客户端调用deepCopy()方法也可以实现深拷贝。