论Java中的深浅拷贝

目录

 

深浅拷贝简介

1.浅拷贝

2.深拷贝

3.总结

深浅拷贝举例

总结


深浅拷贝简介

浅拷贝和深拷贝都是对一个已有对象的操作,编译系统会自动调用一种构造函数——拷贝构造函数,如果用户未定义拷贝构造函数,则会调用默认拷贝构造函。

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));  
      
      
}  

也就是, 如果类中还有引用类型的变量,要连续递归进行拷贝。

总结

浅拷贝:对象值拷贝,对于拷贝而言,拷贝出来的对象仍然保留原对象的所有引用
问题:牵一发而动全身,只要任意一个拷贝对象(或原有对象)中的引用发生改变,所有对象均会受到影响
优点:效率高,相对于深拷贝节约空间
深拷贝:深拷贝出来的对象产生了所有引用的新的对象
问题:深拷贝效率低,且浪费空间。
优点:修改任意一个对象,不会对其他对象产生影响

因此,一般这样进行考虑:延迟拷贝=深拷贝+浅拷贝
读取时使用浅拷贝,如果内容修改时用深拷贝,浅拷贝快于深拷贝

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值