目录
深浅拷贝简介
浅拷贝和深拷贝都是对一个已有对象的操作,编译系统会自动调用一种构造函数——拷贝构造函数,如果用户未定义拷贝构造函数,则会调用默认拷贝构造函。
1.浅拷贝
1. 对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。因为是两份不同的数据,所以对其中一个对象的该成员变量值进行修改,不会影响另一个对象拷贝得到的数据。
2.对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值。
2.深拷贝
设想一下,一个类有一个对象,其成员变量中又有一个对象,该对象指向另一个对象,另一个对象又指向另一个对象,直到一个确定的实例。这就形成了对象图。那么,对于深拷贝来说,不仅要复制对象的所有基本数据类型的成员变量值,还要为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象。也就是说,对象进行深拷贝要对整个对象图进行拷贝!
3.总结
浅拷贝:对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝,此为浅拷贝。
深拷贝:对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容,此为深拷贝。
深浅拷贝举例
public static void main(String[] args) {
int[] a = new int[]{1,2,3};
int[] b = a;
System.out.println(a[0]); //1
System.out.println(b[0]); //1
a[0] = 1000;
System.out.println(a[0]); //1000
System.out.println(b[0]); //1000
System.out.println("a的引用:" +a+"b的引用:"+b); //a的引用:[I@16d3586b的引用:[I@16d3586
}
以上足以说明浅拷贝只是拷贝了引用,两个引用指向同一个对象。
---------------------------------------------------------------------------------------------------------------------------------------
若要实现深拷贝,必须实现cloneable接口,并且重写clone方法。
static class Body implements Cloneable{
public Head head;
public Body() {}
public Body(Head head) {this.head = head;}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
static class Head /*implements Cloneable*/{
public Face face;
public Head() {}
public Head(Face face){this.face = face;}
}
public static void main(String[] args) throws CloneNotSupportedException {
Body body = new Body(new Head());
Body body1 = (Body) body.clone();
System.out.println("body == body1 : " + (body == body1) );
System.out.println("body.head == body1.head : " + (body.head == body1.head));
}
在以上代码中, 有两个主要的类, 分别为Body和Face, 在Body类中, 组合了一个Face对象。当对Body对象进行clone时, 它组合的Face对象只进行浅拷贝。打印结果可以验证该结论:
body == body1 : false
body.head == body1.head : true
如果要使Body对象在clone时进行深拷贝, 那么就要在Body的clone方法中,将源对象引用的Head对象也clone一份。
static class Body implements Cloneable{
public Head head;
public Body() {}
public Body(Head head) {this.head = head;}
@Override
protected Object clone() throws CloneNotSupportedException {
Body newBody = (Body) super.clone();
newBody.head = (Head) head.clone();
return newBody;
}
}
static class Head implements Cloneable{
public Face face;
public Head() {}
public Head(Face face){this.face = face;}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public static void main(String[] args) throws CloneNotSupportedException {
Body body = new Body(new Head());
Body body1 = (Body) body.clone();
System.out.println("body == body1 : " + (body == body1) );
System.out.println("body.head == body1.head : " + (body.head == body1.head));
}
也就是, 如果类中还有引用类型的变量,要连续递归进行拷贝。
总结
浅拷贝:对象值拷贝,对于拷贝而言,拷贝出来的对象仍然保留原对象的所有引用
问题:牵一发而动全身,只要任意一个拷贝对象(或原有对象)中的引用发生改变,所有对象均会受到影响
优点:效率高,相对于深拷贝节约空间
深拷贝:深拷贝出来的对象产生了所有引用的新的对象
问题:深拷贝效率低,且浪费空间。
优点:修改任意一个对象,不会对其他对象产生影响
因此,一般这样进行考虑:延迟拷贝=深拷贝+浅拷贝
读取时使用浅拷贝,如果内容修改时用深拷贝,浅拷贝快于深拷贝