惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

P
Proofpoint News Feed
Blog — PlanetScale
Blog — PlanetScale
GbyAI
GbyAI
C
Check Point Blog
腾讯CDC
Stack Overflow Blog
Stack Overflow Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
The GitHub Blog
The GitHub Blog
A
About on SuperTechFans
Recent Announcements
Recent Announcements
L
LangChain Blog
Microsoft Azure Blog
Microsoft Azure Blog
小众软件
小众软件
J
Java Code Geeks
博客园_首页
Jina AI
Jina AI
美团技术团队
H
Help Net Security
MyScale Blog
MyScale Blog
Engineering at Meta
Engineering at Meta
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
人人都是产品经理
人人都是产品经理
Y
Y Combinator Blog
S
SegmentFault 最新的问题

博客园 - 小飞龙(Jack)

redis消息队列 Redis实现消息队列 BlockingQueue介绍 阻塞的队列 线程安全问题 单线程与多线程的区别 什么场景用到多线程 Java解决高并发秒杀商品 秒杀架构模型设计 大型网站如何防止崩溃,解决高并发带来的问题 序列化与反序列号 普通常用知识汇总 接口和抽象类的区别 详解C#break ,continue, return AJAX原理 比特(bit)与字节(byte)区别,站位比较 NVARCHAR 和VARCHAR区别和使用 C# 中的委托和事件 String、StringBuffer与StringBuilder之间区别
深拷贝与浅拷贝探析
小飞龙(Jack) · 2012-09-11 · via 博客园 - 小飞龙(Jack)

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

考虑以下写法

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

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

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

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

       首先(2)中将source赋给dest,执行了深拷贝动作,其时destsource的值是一样的,都是int.MaxValue;(3)对dest进行修改,dest值变为1024,由于是深拷贝,因此不会运行sourcesource仍然是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

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

5.一些需要注意的东西

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

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