Java的深拷贝和浅拷贝

浅拷贝就是指两个对象共同拥有同一个值,一个对象改变了该值,也会影响到另一个对象。深拷贝就是两个对象的值相等,但是互相独立。

    首先,Java中常用的拷贝操作有三个,operator =、拷贝构造函数 clone()方法。由于Java不支持运算符重载,我们无法在自己的自定义类型中定义operator=。拷贝构造函数大家应该很熟悉,如果我们要使自己定义的对象能够深拷贝,就改写从 Object继承而来的 clone方法,使它的访问权限为 public,因为为了防止意外的支持 clone操作,Object的 clone方法是 protected权限。


    
通过上面的分析,可以看出,如果我们要给自己的类添加拷贝功能,我们可以添加拷贝构造函数和实现Cloneable接口。
    
现在,来看一下不同的类型在拷贝过程中的表现:

类型

=

拷贝构造函数

clone方法

预定义基本类型

深度拷贝

如果支持拷贝构造函数的类型,则是深拷贝

不支持

自定义对象

浅拷贝

取决于实现

取决于实现

预定义结合类型

浅拷贝

会逐个调用每个元素的operator=方法

会逐个调用每个元素的operator=方法



        int y = x;          
     下面是测试代码,首先测试的是预定义非集合类型的 operator = 操作:
        
int  x = 1;

       x = 2;

       /**

        * 如果是浅拷贝的话,应该为true

        */

       System.out.println("int是否为浅拷贝:"+(y==x));

 

 

 

 程序运行后,int是否为浅拷贝:false,测试结果表明,java预定义的非集合类型都是深拷贝。    

而集合类型的拷贝要看存储的元素的类型

,存储的为基本类型就是深度拷贝,是自定义的类型就是浅拷贝。

Student student = new Student();

       student.name = "jiadongfeng";

      

       Student student2= student;

      

       Map<Integer,Student> map = new HashMap<Integer, Student>();

       map.put(1, student2);

       student.name="gudengg";

       Studentstudents = map.get(1);

       System.out.println(students.name);//输出为gudengg


有上图可知,Student student2 =student;student2中只是存储了student的引用,内容会随着student的改变而改变。

而有时我们需要对自己的对象进行深拷贝怎么办呢,这时候我们就是要使我们的类是想clone方法了。

class Student  {

    public Stringname;

 

   

    Public  Object clone()throwsCloneNotSupportedException {

       Studentstudent = new Student();

       student.name = this.name;

       return student;

    }

   

}

Student student = new Student();

       student.name = "jiadongfeng";

      

       Student student2= student.clone();

      

       Map<Integer,Student> map = new HashMap<Integer, Student>();

       map.put(1, student2);

       student.name="gudengg";

       Studentstudents = map.get(1);

       System.out.println(students.name);//输出为jiadongfeng

用图可表示为:


所以,此时student的改变,跟student2是没有关系 的。

 


    
现在,我们来测试预定义集合类型的operator=操作:
        ArrayList list1=new ArrayList();
        list1.add("yangzhou");
        ArrayList list2=list1;
        list1.clear();

        if(list2.isEmpty()){
           System.out.println(“浅拷贝");
        }

    
结果输出为shallow copy

    
现在我来测试拷贝构造函数:
        ArrayList list1=new ArrayList();
        list1.add("yangzhou");
        ArrayList list2=newArrayList(list1);
        list1.clear();

        if(list2.isEmpty()){
           System.out.println("浅拷贝");
        }else{
           System.out.println("深拷贝");
        }

        
输出结果是deep copy;
    clone
方法的测试代码只是将第三行换成list1.clone(),加上类型转换,这里不再贴代码了。结果也证明是深拷贝
    
预定义集合类的深拷贝 实际上就是调用每个元素的operator =。如果元素都是自定义类型的化,实际上还是浅拷贝。现在来看测试代码:
    ArrayList list1=new ArrayList();
        Person p1=new Person();
        p1.setAge(32);
        p1.setName("
陈抒");
        list1.add(p1);

        ArrayList list2=(ArrayList)list1.clone();
       list2.get(0).setName("chenshu");

       if(list2.get(0).getName().equals(list1.get(0).getName())){
           System.out.println("shallow copy");
        }else{
           System.out.println("deep copy");

        }
    
    
输出为shallow copyPerson是自定义类型,它的operator =运算符只是引用之间赋值,是浅拷贝。因此当修改了list2的第一个元素指向的Person对象的name属性,也就是修改了list1第一个元素所指向的Person对象的name属性。对于这种拷贝,我自己起了一个名字,叫做第一层深拷贝。


 
 实际上,所有的问题都是是否是复制了引用这个问题。复制了引用指向的是同一个对象,相当于共享的实际,使用new出来的,自然是新的对象,不管构造怎么写,都依赖于具体构造的代码,想将对象完全复制成一个新象,要new生产一个,被复制的对象有private成员,这才要自己实现clone方法来访问private成员。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值