对象的拷贝 深拷贝和浅拷贝(转)

对象的拷贝 深拷贝和浅拷贝

 

i.关于clone[对象拷贝]——在实际编程过程,有时候我们会遇到一种情况:当 你有一个对象A,在某一个时刻,A已经保存了对应的属性值,而且这些值本身是有效的,这个时候可能需要一个和A完全相同的对象B,并且当B里面的属性值发 生变化的时候,A中的属性值不受影响,可以理解为A和B独立,但是B的初始化不是按照我们平时创建该对象的时候的初始化操作,B的初始化数据完全来自A。 对Java存储模型了解的人都明白,在Java里面如果针对两个对象引用采取赋值操作的时候,仅仅是让两个引用指向了同一对象,如果其中一个引用里面的对 象属性改变的时候会影响另外一个对象属性跟着改变,所以Java语言本身的对象赋值语句是不能完成上边的需求的。在这种时候,就需要用到Object类里 面的通用方法clone(),这里需要说明的是:
  通过clone()方法创建的对象是一个新对象,它可以认为是源对象的一个拷贝,但是在内存堆中,JVM会为这个拷贝分配新的对象存储空间来存放该对象的所有状态
  该拷贝和普通对象使用new操作符创建的对象唯一的区别在于初始值,这个拷贝的初始值不是对象里面成员的默认值,而是和源对象此刻状态的成员的值是一样的
  下边这段代码是clone方法的运用:
public class Testing {
    public static void main(String args[]){
        AClass class1 = new AClass();
        class1.a = 12;
        AClass class2 = (AClass)class1.clone();
        System.out.println(class2.a);
        System.out.println(class1==class2);
    }
}

class AClass implements Cloneable{
    public int a = 0;
    public Object clone(){
        AClass o = null;
        try{
            o = (AClass)super.clone();
        }catch(CloneNotSupportedException ex){
            ex.printStackTrace();
        }
        return o;
    }
}
  上边这段代码运行结果输出为:
12
false
  可以知道的就是成功复制了一个AClass的对象,该对象的引用为 class1,而拷贝对象的引用为class2,这两个引用通过==比较输出为false,证明这两个引用不是指向了同一个对象,而且拷贝对象里面的a的 值和class1引用的对象里面的a的值是一样的,都是12,这样就成功完成了对象的拷贝过程。若你对上边这段代码还有不了解的地方可以尝试将下边的代码 修改掉:
AClass class2 = (AClass)class1.clone() 修改为:AClass class2 = class1;
  改了过后,输出结果应该为:
12
true
  所以在对象的clone过程,需要注意的几点有:
  [1]希望能够提供对象clone功能的类必须实现Cloneable接口,这个接口位于java.lang包里面
  [2]希望提供对象clone功能的类必须重载clone()方法,在重载过程可以看到这句话:super.clone();也就是说,不论clone类的继承结构如何,我们在对象拷贝的时候都直接或简介调用了Object的clone()方法。而且细心留意可以看到Object的clone方法是protected域的,也就是说这个方法只有Object的子类可以调用,而在重载的时候将clone方法修饰符改为public
  [3]还有一点很重要就是Object源代码里面的clone()方法是native方法一般而言,对JVM来说,native方法的效率远比java中的普通方法高,这就是为什么我们在复制一个对象的时候使用Object的clone()方法,而不是使用new的方式。
  [4]Cloneable接口和我们在编写IO程序的时候序列化接口一 样,只是一个标志,这个接口是不包含任何方法的,这个标志主要是为了检测Object类中的clone方法,若我们定义的类想要实现拷贝功能,但是没有实 现该接口而调用Object的clone方法,那么就会出现语句中catch块里面的异常错误,抛出 CloneNotSupportedException。
  ii浅拷贝——在对象clone的过程中,浅拷贝又称为“影子clone”,先看一段代码:
//这里先定义一个类
class AClass{
    public int a;
    public AClass(int a){ this.a = a;}
    public void change(){ a += 12;}
    public String toString(){ return "A Value is " + this.a;}
}
//定义一个clone类,里面包含了AClass的对象引用
class BClass implements Cloneable{
    public int a = 12;
    public AClass obj = new AClass(11);
    public Object clone(){
        BClass object = null;
        try{
            object = (BClass)super.clone();
        }catch(CloneNotSupportedException ex){
            ex.printStackTrace();
        }
        return object;
    }
}

public class TestClone {
    public static void main(String args[]){
        BClass class1 = new BClass();
        class1.a = 15;

        System.out.println(class1.a);
        System.out.println(class1.obj);
        BClass class2 = (BClass)class1.clone();
        class2.a = 22;
        class2.obj.change();
        System.out.println(class1.a);
        System.out.println(class1.obj);
        System.out.println(class2.a);
        System.out.println(class2.obj);
    }
}
  运行上边这段代码会有以下输出:
15
A Value is 11
15                    //这里拷贝成功了
A Value is 23     //!!!不对,根本没有调用class1里面的obj的change方法,所以不应该修改class1里面的obj里面的变量a的值【初衷】
22
A Value is 23
  不知细心的读者有没有发现输出和我们预期的拷贝不一样,虽然 class2引用的对象是从class1拷贝过来的,class2里面的引用obj和class1里面的引用obj实际上还是指向了同一个对象,其含义在 于,拷贝的初衷是要复制一个一模一样的对象,包括对象里面的对象也应该实现的是复制操作,它最终的目的是保证class1和class2本身的属性以及 class1和class2里面的对象引用的属性在拷贝过后的各种相关操作里面相互独立,上边输出证明了class1和class2里面的变量a确实已经 拷贝成功,但是class1和class2里面的AClass对象的引用obj在拷贝过后还是指向了同一个对象,所以拷贝结束过后,调用class2的 obj的change方法的时候,也修改了class1里面的obj指向的对象里面的值。所以在Java里面我们把上边的拷贝过程称为“浅拷贝”,同样又 称为“影子clone”。
  从这里可以知道,在JVM的对象复制里面,实际上基本数据类型可以直接通过这种方式来进行拷贝工作,而非原始类型这样操作了过后拷贝的对象仅仅拷贝了对象里面的基本数据类型的成员变量,而比较复杂的类型的成员变量并没有像预期一样产生拷贝效果,这种拷贝我们就称之为“浅拷贝”。
  iii.深拷贝——如果要实现我们预期的对象拷贝效果,就需要使用深拷贝操作,其实在浅拷贝基础上实现深拷贝有两个步骤,以上边的代码为例:
  [1]第一步:让AClass实现同样的clone功能
  [2]第二步:在BClass的clone操作中多写入一句话:object.obj = (AClass)obj.clone();
(本文来自互联网)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值