`
zwt2001267
  • 浏览: 435825 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

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

阅读更多

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

 

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();
(本文来自互联网)
分享到:
评论

相关推荐

    C#中的浅拷贝和深拷贝

    C#中的浅拷贝和深拷贝 C#中有两种类型变量,一种是值类型变量,一种是引用类型变量。

    Python 深拷贝和浅拷贝详解

    深拷贝,是指重新分配一块内存,创建一个新的对象,并且将原对象中的元素,以递归的方式,通过创建新的子对象拷贝到新对象中。因此,新对象和原对象没有任何关联。 2、浅拷贝 使用数据类型本身的构造器 对于可变的...

    Python中列表和数组的赋值以及-浅拷贝和深拷贝的实例讲解

    对Python中列表和数组的赋值 中 ,浅拷贝和深拷贝的实例讲解 浅 引⽤: 列表赋值: 1234567>>> a = [1, 2, 3] >>> b = a >>> print b [1, 2, 3] >>> a[0] = 0 >>> print b [0, 2, 3] 解释:[1, 2, 3]被视作⼀个对象...

    python浅拷贝、深拷贝

    下面是对浅拷贝和深拷贝的描述: 浅拷贝:浅拷贝是创建一个新的对象,该对象与原始对象共享内部元素的引用。换句话说,浅拷贝只复制了对象的第一层元素,而没有递归复制其内部嵌套的对象。因此,当修改原始对象的...

    浅析Java中的深拷贝与浅拷贝

    首先我们看看浅拷贝和深拷贝的定义 浅拷贝:只复制一个对象,对象内部存在的指向其他对象数组或者引用则不复制 深拷贝:对象,对象内部的引用均复制 为了更好的理解它们的区别我们假设有一个对象A,它包含...

    JS赋值、浅拷贝和深拷贝(数组和对象的深浅拷贝)实例详解

    本文实例讲述了JS赋值、浅拷贝和深拷贝(数组和对象的深浅拷贝)。分享给大家供大家参考,具体如下: 深拷贝和浅拷贝是只针对Object和Array这样的引用数据类型的。  浅拷贝 只是拷贝了基本类型的数据,而引用类型...

    【JavaScript源代码】详解JS变量存储深拷贝和浅拷贝.docx

     目录 变量类型与存储空间栈内存和堆内存基本数据类型引用类型图解存储空间引用类型的赋值深拷贝和浅拷贝深拷贝浅拷贝对象的赋值三者对比浅拷贝的常用的五种方法Object.assign()扩展运算符Array.prototype.slice...

    java对象的深拷贝和浅拷贝[归类].pdf

    java对象的深拷贝和浅拷贝[归类].pdf

    C++类对象的深拷贝、浅拷贝构造函数.doc

    C++类对象的深拷贝、浅拷贝构造函数,浅拷贝构造函数详细解释,很好的

    Python 拷贝对象(深拷贝deepcopy与浅拷贝copy)

    import copya = [1, 2, 3, 4, [‘a’, ‘b’]] #原始对象b = a #赋值,传对象的引用c = copy.copy(a) #对象拷贝,浅拷贝d = copy.deepcopy(a) #对象拷贝,深拷贝a.append(5) #修改对象aa[4]....

    《剑指offer》Java浅拷贝和深拷贝.pdf

    Java 对象拷贝是为对象赋值的一种方式,简单来说就是创建一个和原对象相同的对象,新创建的对象是原对象的一个副本,面试官贼拉喜欢在面试的时候问一问你浅拷贝和深拷贝的原理。因为它涉及到对象的引用关系,涉及到 ...

    深拷贝浅拷贝.zip

    该例子代码主要实现C#的浅拷贝和深拷贝,深拷贝是通过复制对象和序列化对象两种方法分别实现的。各位同学各取所需。

    java深入理解浅拷贝和深拷贝

    本文将会深入的探讨一下在拷贝对象中会出现的浅拷贝和深拷贝的情况。 拷贝接口 java中所有的对象都是继承自java.lang.Object。Object对象中提供了一个clone方法,来供我们对java对象进行拷贝。 protected native ...

    Python 112.对象的浅拷贝和深拷贝_内存分析.mp4

    Python 112.对象的浅拷贝和深拷贝_内存分析.mp4

    JavaScript深拷贝和浅拷贝概念与用法实例分析

    但是根据新生成的对象能否影响到原对象可以分为浅拷贝和深拷贝。 概念1:浅拷贝 浅拷贝就是指拷贝引用,新生成的引用和原来的引用都是指向同一个对象的实例,彼此之间的操作会相互影响。 概念2:深拷贝 在堆中重新...

    js对象浅拷贝和深拷贝详解

    本文为大家分享了JavaScript对象的浅拷贝和深拷贝代码,供大家参考,具体内容如下 1.浅拷贝 拷贝就是把父对像的属性,全部拷贝给子对象。 下面这个函数,就是在做拷贝: var Chinese = {  nation:'中国' } var ...

    C++类对象的深拷贝、浅拷贝构造函数[借鉴].pdf

    C++类对象的深拷贝、浅拷贝构造函数[借鉴].pdf

    对浅拷贝、深拷贝、写时拷贝的简单认识

    浅拷贝 也称位拷贝或值拷贝。如果对象中管理资源,编译器只是将对象中的值拷贝过来,就会导致多个资源共享一份资源,当一个对象销毁时就会将该资源释放,而这时另一些对象不知道该资源已经被释放,以为还有效,所以...

    JavaScript对象的浅拷贝与深拷贝实例分析

    本文实例讲述了JavaScript对象的浅拷贝和深拷贝。分享给大家供大家参考,具体如下: 1、浅拷贝 仅仅复制对象的引用,而不是对象本身。 var person = { name: 'Alice', friends: ['Bruce', 'Cindy'] } var student...

Global site tag (gtag.js) - Google Analytics