跟着小欢子把深拷贝、浅拷贝、引用拷贝彻底分清楚吧!
首先介绍一下我们会使用到的两个类Demo1,Demo2(为了方便我们实验,就不进行封装处理啦)。
public class Demo1 {
String name;
int age;
@Override
public String toString() {
return "Demo1{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Demo2 {
String name;
int age;
Demo1 demo;
@Override
public String toString() {
return "Demo2{" +
"name='" + name + '\'' +
", age=" + age +
", demo=" + demo +
'}';
}
}
引用拷贝
引用拷贝就是我们最常用直接赋值啦,直接上代码!
实验1
public static void main(String[] args) {
Demo1 demo1=new Demo1();
demo1.name="xiaohuanzi";
demo1.age=25;
Demo1 tempDemo=demo1;
tempDemo.name="yuanyuan";
tempDemo.age=18;
System.out.println(tempDemo);
System.out.println(demo1);
}
实验1运行结果
Demo1{name='yuanyuan', age=18}
Demo1{name='yuanyuan', age=18}
通过运行实验1运行结果可知,当我们进行引用拷贝时,拷贝是对象的地址,即tempDemo指向的也是demo1,所以当我们修改tempDemo时,其实修改的是tempDemo指向的对象,因此demo1也会跟着变化。
浅拷贝
谈到浅拷贝,就需要我们继承接口Cloneable,并重写clone方法啦,我们对Demo1,Demo2稍作修改。
public class Demo1 implements Cloneable{
String name;
int age;
@Override
public String toString() {
return "Demo1{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Demo2 implements Cloneable{
String name;
int age;
Demo1 demo;
@Override
public String toString() {
return "Demo2{" +
"name='" + name + '\'' +
", age=" + age +
", demo=" + demo +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
实验2
public static void main(String[] args) {
Demo2 demo2=new Demo2();
demo2.name="xiaohuanzi";
demo2.age=25;
Demo1 demo1=new Demo1();
demo1.name="congcong";
demo1.age=25;
demo2.demo=demo1;
try {
Demo2 tempDemo=(Demo2)demo2.clone();
tempDemo.name="yuanyuan";
tempDemo.age=18;
tempDemo.demo.name="404";
tempDemo.demo.age=18;
System.out.println(demo2);
System.out.println(tempDemo);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
试验2的运行结果
Demo2{name='xiaohuanzi', age=25, demo=Demo1{name='404', age=18}}
Demo2{name='yuanyuan', age=18, demo=Demo1{name='404', age=18}}
从实验2的运行结果可以看到,当我们通过clone方法进行拷贝后,修改拷贝对象tempDemo的基本数据类型name,age并不会影响原对象,但是修改引用类型成员demo仍然会影响原对象。因此我们可以得出一个结论,浅拷贝确实是重新创建了一个实例,但是实例内部的引用类型成员依旧是引用拷贝。
深拷贝
深拷贝的实现需要我们在Demo2重写的clone方法里面再次进行修改,如下:
@Override
protected Object clone() throws CloneNotSupportedException {
Demo2 demo2=(Demo2)super.clone();
demo2.demo=(Demo1) demo2.demo.clone();
return demo2;
}
实验3
public static void main(String[] args) {
Demo2 demo2=new Demo2();
demo2.name="xiaohuanzi";
demo2.age=25;
Demo1 demo1=new Demo1();
demo1.name="congcong";
demo1.age=25;
demo2.demo=demo1;
try {
Demo2 tempDemo=(Demo2)demo2.clone();
tempDemo.name="yuanyuan";
tempDemo.age=18;
tempDemo.demo.name="404";
tempDemo.demo.age=18;
System.out.println(demo2);
System.out.println(tempDemo);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
实验3的运行结果
Demo2{name='xiaohuanzi', age=25, demo=Demo1{name='congcong', age=25}}
Demo2{name='yuanyuan', age=18, demo=Demo1{name='404', age=18}}
通过实验3的运行结果我们可以得知,通过深拷贝后,修改拷贝对象tempDemo并不会影响原对象,包括基本数据类型成员以及引用类型成员。