`
reb12345reb
  • 浏览: 50181 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

深拷贝与浅拷贝

 
阅读更多

深入谈谈java的深拷贝与浅拷贝

首先我们看看浅拷贝和深拷贝的定义

浅拷贝:只复制一个对象,对象内部存在的指向其他对象数组或者引用则不复制

深拷贝:对象,对象内部的引用均复制

为了更好的理解它们的区别我们假设有一个对象A,它包含有2对象对象A1和对象A2(图1)


 

对象A进行浅拷贝后,得到对象B但是对象A1和A2并没有被拷贝(图2)


 

对象A进行深拷贝,得到对象B的同时A1和A2连同它们的引用也被拷贝(图3)


 

在理解了深拷贝和浅拷贝后,我们来看看java的深拷贝和浅拷贝实现。java.lang.Object的clone()方法默认是返回一个前拷贝对象。 因此如果要用clone()方法实现一个深拷贝,我们必须对每个对象的clone()方法进行特别实现。当对象层次复杂的时候,这样做不但困难而且浪费时 间和容易出现错误,特别有时候你不但需要深拷贝同时你也对这个对象进行浅拷贝的时候,你会发现写这个clone()方法真不是一个好的解决方案。

 

那么除了clone()方法,我们还可以怎么实现呢?答案是序列化,实现步骤和思路是把要拷贝的对象输出成byte array,然后再利用ObjectInputStream转换出新的对象。下面是代码

Java代码
    	public static Object copy(Object oldObj) {
    		Object obj = null;
    		try {
    			// Write the object out to a byte array
    			ByteArrayOutputStream bos = new ByteArrayOutputStream();
    			ObjectOutputStream out = new ObjectOutputStream(bos);
    			out.writeObject(oldObj);
    			out.flush();
    			out.close();
    
    			// Retrieve an input stream from the byte array and read
    			// a copy of the object back in.
    			ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); 
    			ObjectInputStream in = new ObjectInputStream(bis);
    			obj = in.readObject();
    		} catch (IOException e) {
    			e.printStackTrace();
    		} catch (ClassNotFoundException cnfe) {
    			cnfe.printStackTrace();
    		}
    		return obj;
    	}

      1.   深拷贝是指源对象与拷贝对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响。举个例子,一 个人名叫张三,后来用他克隆(假设法律允许)了另外一个人,叫李四,不管是张三缺胳膊少腿还是李四缺胳膊少腿都不会影响另外一个人。比较典型的就是 Value(值)对象,如预定义类型Int32,Double,以及结构(struct),枚举(Enum)等。

    考虑以下写法

           int source = int.MaxValue;//(1)初始化源对象为整数的最大值2,147,483,647

                int dest = source;//(2)赋值,内部执行深拷贝

                dest = 1024;//(3)对拷贝对象进行赋值

                source = 2048;//(4)对源对象进行赋值

           首先(2)中将source赋给dest,执行了深拷贝动作,其时dest和source的值是一样的,都是int.MaxValue;(3)对dest 进行修改,dest值变为1024,由于是深拷贝,因此不会运行source,source仍然是int.MaxValue;(4)对source进行了 修改,同样道理,dest仍然是1024,同时int.MaxValue的值也不变,仍然是2,147,483,647;只有source变成了 2048。

           再考虑以下写法

            struct Point

            {

                public int X;

                public int Y;

                public Point(int x, int y)

                {

                    X = x;

                    Y = y;

                }

            }

     

            Point source = new Point(10, 20);

            Point dest = source;

     

            dest.X = 20

         当dest.X属性变成20后,source的X属性仍然是10

    2.       浅拷贝是指源 对象与拷贝对象共用一份实体,仅仅是引用的变量不同(名称不同)。对其中任何一个对象的改动都会影响另外一个对象。举个例子,一个人一开始叫张三,后来改 名叫李四了,可是还是同一个人,不管是张三缺胳膊少腿还是李四缺胳膊少腿,都是这个人倒霉。比较典型的就有Reference(引用)对象,如 Class(类)。

    考虑以下写法

            class Point

            {

                public int X;

                public int Y;

                public Point(int x, int y)

                {

                    X = x;

                    Y = y;

                }

            }

     

            Point source = new Point(10, 20);

            Point dest = source;

       dest.X = 20;

    由于Point现在是引用对象,因此Point dest=source的赋值动作实际上执行的是浅拷贝,最后的结果应该是source的X字段值也变成了20。即它们引用了同一个对象,仅仅是变量明source和dest不同而已。

    3.  引用对象的浅拷贝原理

    引用对象之间的赋值之所以执行的是浅拷贝动作,与引用对象的特性有关,一个引用对象一般来说由两个部分组成

    (1)一个具名的Handle,也就是我们所说的声明(如变量)

    (2)一个内部(不具名)的对象,也就是具名Handle的内部对象。它在Manged Heap(托管堆)中分配,一般由新增引用对象的New方法是进行创建

           如果这个内部对象已被创建,那么具名的Handle就指向这个内部对象在Manged Heap中的地址,否则就是null(从某个方面来讲,如果这个具名的handle可以被赋值为null,说明这是一个引用对象,当然不是绝对)。两个引 用对象如果进行赋值,它们仅仅是复制这个内部对象的地址,内部对象仍然是同一个,因此,源对象或拷贝对象的修改都会影响对方。这也就是浅拷贝

    4.引用对象如何进行深拷贝

    由于引用对象的赋值仅仅是复制具名Handle(变量)指向的地址,因此要对引用对象进行深拷贝就要重新创建一份该对象的实例,并对该对象的字段进行逐一赋值,如以下写法

            class Point

            {

                public int X;

                public int Y;

                public Point(int x, int y)

                {

                    X = x;

                    Y = y;

                }

            }

     

            Point source = new Point(10, 20);

            Point dest = new Point(source.X, source.Y);

            //或以下写法

            //Point dest = new Point()

            //dest.X = source.X

       //dest.Y = source.Y

           其时,source和dest就是两个互相独立的对象了,两者的修改都不会影响对方

     

    5.一些需要注意的东西

           (1):String字符串对象是引用对象,但是很特殊,它表现的如值对象一样,即对它进行赋值,分割,合并,并不是对原有的字符串进行操作,而是返回一个新的字符串对象

           (2):Array数组对象是引用对象,在进行赋值的时候,实际上返回的是源对象的另一份引用而已;因此如果要对数组对象进行真正的复制(深拷贝),那么需要新建一份数组对象,然后将源数组的值逐一拷贝到目的对象中

    分享到:
    评论

    相关推荐

      js深拷贝与浅拷贝详解以及例子.pdf

      JS 深拷贝与浅拷贝详解以及例子 深拷贝与浅拷贝是 JavaScript 开发中常见的概念,分别对应着不同的拷贝方式。在本文中,我们将详细介绍浅拷贝和深拷贝的概念、特点、实现方法和实例。 一、浅拷贝 浅拷贝只拷贝一...

      javaSE-深拷贝与浅拷贝

      javaSE-深拷贝与浅拷贝

      深拷贝与浅拷贝;copy与mutableCopy;容器类型的深拷贝;copy和strong;

      1、只有NS类型调用copy方法才是浅拷贝,其他的情况全是深拷贝 2、容器类调用copy或mutableCopy能出现的深拷贝的情况下,只是容器的深拷贝,而非容器内元素的深拷贝 3、无论是声明NSString还是NSMutableString类型的...

      03-深拷贝与浅拷贝.html

      03-深拷贝与浅拷贝

      java设计模式【之】原型模式、深拷贝与浅拷贝【源码】【场景:克隆羊】

      java设计模式【之】原型模式、深拷贝与浅拷贝【源码】【场景:克隆羊】 * 原型模式(Prototype) * 实现方式: * 需要被克隆的 class类, 重写Object中的clone()方法,并实现Cloneable接口(否则报错 ...

      深拷贝和浅拷贝一些例子

      深拷贝和浅拷贝一些例子

      copy的使用(深拷贝、浅拷贝)

      让我们深入探讨一下深拷贝与浅拷贝的概念及其应用场景。 ### 浅拷贝(Shallow Copy) 浅拷贝是创建一个新对象,这个新对象含有原对象的所有元素,但这些元素只是原始对象中的引用。也就是说,如果原始对象包含可变...

      通过源码分析iOS中的深拷贝与浅拷贝

      在iOS开发中,深拷贝和浅拷贝是两个关键概念,它们涉及到对象复制时内存管理的细节。本文将从源码角度深入解析这两种拷贝方式。 首先,我们需要明确深拷贝和浅拷贝的基本定义。浅拷贝,也称为指针拷贝,意味着拷贝...

      C++深拷贝浅拷贝

      根据提供的标题、描述和部分无法识别的内容,我们将围绕“C++深拷贝与浅拷贝”的主题进行深入探讨。在C++编程语言中,深拷贝(Deep Copy)与浅拷贝(Shallow Copy)是对象复制时经常遇到的概念。它们在内存管理和...

      深入理解JavaScript中的深拷贝与浅拷贝:实现方法与应用场景

      然而,复制行为可以根据对象内部属性的引用方式被区分为深拷贝和浅拷贝。理解这两者之间的区别对于编写正确和高效的代码至关重要。本文将详细探讨JavaScript中的深拷贝和浅拷贝,包括它们的定义、实现方法以及在不同...

      Java Clone深拷贝与浅拷贝的两种实现方法

      Java Clone 深拷贝与浅拷贝的两种实现方法 Java Clone 是 Java 语言中的一种复制对象的机制,它可以将一个对象的所有属性和状态复制到另一个对象中,实现对象的深拷贝和浅拷贝。下面我们将讨论 Java 中的深拷贝和浅...

      46_深拷贝与浅拷贝的区别1

      而深拷贝则是创建一个全新的、与原始对象完全独立的对象,新对象的属性和值都是原始对象的副本,它们在内存中占据不同的位置,所以修改其中一个对象不会影响另一个。 接着,我们转向C++,在C++中,浅拷贝通常由默认...

      深拷贝拷贝的是内容,浅拷贝拷贝的是指针

      ### 深拷贝与浅拷贝的概念及应用 #### 一、深拷贝与浅拷贝的区别 在计算机编程领域中,深拷贝(Deep Copy)与浅拷贝(Shallow Copy)是两种常见的对象复制方法。这两种方法在处理复杂数据结构(如数组、列表等)时...

      JavaScript中的深拷贝与浅拷贝:技术解析与代码实现

      浅拷贝和深拷贝各有适用场景。浅拷贝适用于只需复制对象第一层属性且不涉及修改引用类型属性的场景,而深拷贝适用于需要完全独立的数据副本,尤其是处理嵌套对象或数组时。在选择拷贝方法时,应根据实际需求和性能...

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

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

      数组的深拷贝与浅拷贝以及数组拷贝的几种方式比较

      目录一、深拷贝与浅拷贝解析浅拷贝深拷贝二、数组拷贝的方式1.for循环来拷贝2.System.arraycopy( )拷贝3.Arrays.copyOf( )拷贝4.clone( )拷贝5.解释三、四种拷贝方式效率比较1. System.arraycopy( )2.Arrays.copyOf...

      C++之深拷贝和浅拷贝

      拷贝构造函数可以执行浅拷贝或深拷贝。浅拷贝是按位拷贝成员,这可能会导致共享数据导致的错误。深拷贝则创建了原始数据的全新副本,避免了共享数据的问题。接下来,我们详细探讨浅拷贝和深拷贝的区别、问题所在以及...

      Python深拷贝与浅拷贝用法实例分析

      本文实例讲述了Python深拷贝与浅拷贝用法。分享给大家供大家参考,具体如下: 1、对象的赋值 对象的赋值实际上是对象之间的引用:当创建一个对象,然后将这个对象赋值给另外一个变量的时候,python并没有拷贝这个...

      从深拷贝、浅拷贝构造函数问题

      #### 四、问题核心——浅拷贝与深拷贝 ##### 浅拷贝(Shallow Copy) - **定义:** 浅拷贝是指当创建一个新的对象时,仅仅复制了原对象的引用而不是创建一个新的副本。 - **示例:** 在本例中,当`a1->push_back...

    Global site tag (gtag.js) - Google Analytics