浅拷贝、深拷贝、完全拷贝

在这里介绍三个概念:
浅拷贝:在拷贝操作时,对于被拷贝的对象的每一层拷贝都是指针拷贝。
深拷贝:在拷贝操作时,对于被拷贝的对象至少有一层拷贝是对象拷贝。
完全拷贝:在拷贝操作时,对于被拷贝的对象的每一层拷贝都是对象拷贝。

  • 1.在拷贝操作时,对于对象有n层是对象拷贝,我们可称作n级深拷贝,此处n应大于等于1。
  • 2.对于完全拷贝如何实现(目前通用的办法是:迭代法和归档),这里后续是否添加视情况而定,暂时不做讲解。
  • 3.指针拷贝俗称指针拷贝,对象拷贝也俗称内容拷贝。
  • 4.一般来讲,浅层拷贝, 拷贝引用对象的指针;深层拷贝, 拷贝引用对象内容。这种定义在多层拷贝的时候,就显得模糊。所以本文定义与它并不矛盾。反而是对它的进一步理解和说明。

深浅拷贝对比

上面说了, 关于 copy, 对于不可变对象是浅拷贝,引用计数每次加一。始终返回一个不可变对象; 对于可变对象为深拷贝,引用计数不改变。所以我们就按照可变和不可变来分别介绍, 由于还涉及到深拷贝和完全拷贝, 所以又按照容器类和非容器类分别来介绍。故分了四大类:非容器类不可变对象, 容器类不可变数组, 非容器类可变对象, 容器类可变数组。

注: 下面整理的 demo 中str1用的是常量区的字符串, 所以在引用计数时, 会是无穷大。 如果有兴趣可以改为堆区对象, 这样引用计数会正常。 其他的方面不会影响到本测试。

非容器类不可变对象

NSString *str1=[NSString stringWithFormat:@"我屮艸芔茻"];
//    NSString *str1=@"one day";printf("\n初始化引用计数为:%lu",str1.retainCount);
NSString *strCopy1=[str1 retain];
printf("\nretain引用计数为:%lu",str1.retainCount);
NSString *strCopy2=[str1 copy];
printf("\ncopy后引用计数为:%lu",str1.retainCount);
NSString *strCopy3=[str1 mutableCopy];
printf("\n继续mutableCopy后为:%lu\n",str1.retainCount);printf("\n非容器类不可变对象");
printf("\n原始地址:%p",str1);
printf("\nretain拷贝:%p",strCopy1);
printf("\ncopy拷贝:%p",strCopy2);
printf("\nmutableCopy拷贝:%p",strCopy3);

打印结果:

初始化引用计数为:1
retain引用计数为:2
copy后引用计数为:3
继续mutableCopy后为:3
非容器类不可变对象
原始地址:_0x60400025c260
retain拷贝:0x60400025c260
copy拷贝:0x60400025c260
mutableCopy拷贝:0x600000059c20

容器类不可变对象

NSArray *array1= [NSArray arrayWithObjects:@"a",@"b",@"c",@"d",nil];printf("\n初始化引用计数为:%lu",array1.retainCount);
NSArray *arrayCopy1 = [array1 retain];
printf("\nretain后引用计数为:%lu",array1.retainCount);
NSArray *arrayCopy2 = [array1 copy];
printf("\ncopy后引用计数为:%lu",array1.retainCount);
NSArray *arrayCopy3 = [array1 mutableCopy];
printf("\nmutableCopy后引用计数为:%lu\n",array1.retainCount);printf("\n容器类不可变数组");
printf("\n原始地址:%p\t%p",array1,[array1 objectAtIndex:1]);
printf("\nretain拷贝:%p\t%p",arrayCopy1,[arrayCopy1 objectAtIndex:1]);
printf("\ncopy拷贝:%p\t%p",arrayCopy2,[arrayCopy2 objectAtIndex:1]);
printf("\nmutableCopy拷贝:%p\t%p",arrayCopy3,[arrayCopy3 objectAtIndex:1]);

打印结果:

初始化引用计数为:1
retain后引用计数为:2
copy后引用计数为:3
mutableCopy后引用计数为:3
容器类不可变数组
原始地址:0x600000444050 0x10fef20b0
retain拷贝:0x600000444050 0x10fef20b0
copy拷贝:0x600000444050 0x10fef20b0
mutableCopy拷贝:0x600000444170 0x10fef20b0

非容器类可变对象

NSMutableString *str2=[NSMutableString stringWithString:@"two day"];printf("\n初始化引用计数为:%lu",str2.retainCount);
NSMutableString *strCpy1=[str2 retain];
printf("\nretain后引用计数为:%lu",str2.retainCount);
NSMutableString *strCpy2=[str2 copy];
printf("\ncopy后引用计数为:%lu",str2.retainCount);
NSMutableString *strCpy3=[str2 mutableCopy];
printf("\nmutableCopy后引用计数为:%lu\n",str2.retainCount);printf("\n非容器类可变对象");
printf("\n原始地址:%p",str2);
printf("\nretin拷贝:%p",strCpy1);
printf("\ncopy拷贝:%p",strCpy2);
printf("\nmutableCopy拷贝:%p",strCpy3);

打印结果:

初始化引用计数为:1
retain后引用计数为:2
copy后引用计数为:2
mutableCopy后引用计数为:2
非容器类可变对象
原始地址:0x6000004441a0
retin拷贝:_0x6000004441a0
copy拷贝:0xa796164206f77747
mutableCopy拷贝:0x600000444140

容器类可变对象

NSMutableArray *array2   = [NSMutableArray arrayWithObjects:@"aa",@"bb",@"cc",@"dd",nil];printf("\n初始化引用计数为:%lu",array2.retainCount);
NSMutableArray *arrayCpy1 = [array2 retain];
printf("\nretain后引用计数为:%lu",array2.retainCount);
NSMutableArray *arrayCpy2=[array2 copy];
printf("\ncopy后引用计数为:%lu",array2.retainCount);
NSMutableArray *arrayCpy3 = [array2 mutableCopy];
printf("\nmutableCopy后引用计数为:%lu\n",array2.retainCount);printf("\n容器类可变数组");
printf("\n原始地址::%p\t%p",array2,[array2 objectAtIndex:1]);
printf("\nretain拷贝:%p\t%p",arrayCpy1,[arrayCpy1 objectAtIndex:1]);
printf("\ncopy拷贝:%p\t%p",arrayCpy2,[arrayCpy2 objectAtIndex:1]);
printf("\nnmutableCopy拷贝:%p\t%p",arrayCpy3,[arrayCpy3 objectAtIndex:1]);

打印结果:

初始化引用计数为:1
retain后引用计数为:2
copy后引用计数为:2
mutableCopy后引用计数为:2
容器类可变数组
原始地址::0x60400025c2f0 0x10fef2150
retain拷贝:_0x60400025c2f0 0x10fef2150
copy拷贝:_0x60400025c080 0x10fef2150
nmutableCopy拷贝:0x60400025bf90 0x10fef2150

应用

1、不可变对象→可变对象的转换:

NSArray *array1= [NSArray arrayWithObjects:@"a",@"b",@"c",@"d",nil];
NSMutableArray  *str2=[array1 mutableCopy];

2、可变对象→不可变对象的转换:

NSMutableArray *array2 = [NSMutableArray arrayWithObjects:@"aa",@"bb",@"cc",@"dd",nil];
NSArray *array1 = [array2 Copy];

3、可变对象→可变对象的转换(不同指针变量指向不同的内存地址):

NSMutableArray *array1 = [NSMutableArray arrayWithObjects:@"a",@"b",@"c",@"d",nil];
NSMutableArray *str2 = [array1 mutableCopy];

通过上边的两个例子,我们可轻松的将一个对象在可变和不可变之间转换,并且这里不用考虑内存使用原则(即引用计数的问题)。没错,这就是深拷贝的魅力了。

4、同类型对象之间的指针拷贝(不同指针变量指向同一块内存地址):

  //a、NSMutableString *str1 = [NSMutableString stringWithString:@"two day"];NSMutableString *str2 = [str1 retain];[str1  release];//b、NSArray *array1 = [NSArray arrayWithObjects:@"a",@"b",@"c",@"d",nil];NSArray *str2 = [array1 Copy];[array1 release];

应用总结:
1.深拷贝是在要将一个对象从可变(不可变)转为不可变(可变)或者将一个对象内容克隆一份时用到;
2.浅拷贝是在要拷贝一个对象的指针时用到。
3.深拷贝赋值过程:输入数据→寄存器处理→开辟内存→写入数据。
一次深拷贝,可以得到被拷贝对象指针,并进行一次赋值操作。

对于深拷贝和完全拷贝, 下篇文章深拷贝和完全拷贝对比的探究会具体谈一谈.

关于浅拷贝、深拷贝的探究相关推荐

  1. Interview:算法岗位面试—10.11下午—上海某公司算法岗位(偏机器学习,互联网数字行业)技术面试考点之XGBoost的特点、python的可变不可变的数据类型、赋值浅拷贝深拷贝区别

    ML岗位面试:10.11下午-上海某公司算法岗位(偏机器学习,互联网数字行业)技术面试考点之XGBoost的特点.python的可变不可变的数据类型.赋值浅拷贝深拷贝区别 Interview:算法岗位 ...

  2. 浅显易懂的浅拷贝深拷贝来了

    1.基本数据类型,引用数据类型 说起深拷贝浅拷贝,必须先说数据类型.在拷贝数据的时候才能看出真正差异. 基本数据类型: string,number,boolean,undefined,null, 基本 ...

  3. Clone方法与浅拷贝深拷贝

    Clone方法与浅拷贝&深拷贝 介绍 如何实现 浅拷贝 shallow copy 深拷贝 deep copy 数组中的clone 介绍 在Java中,如果需要创建一个对象的副本,特别是这个对象 ...

  4. 一文搞懂JS中的赋值·浅拷贝·深拷贝

    前言 为什么写拷贝这篇文章?同事有一天提到了拷贝,他说赋值就是一种浅拷贝方式,另一个同事说赋值和浅拷贝并不相同.我也有些疑惑,于是我去MDN搜一下拷贝相关内容,发现并没有关于拷贝的实质概念,没有办法只 ...

  5. python3 赋值 浅拷贝 深拷贝 简介

    目录 一.赋值 二.浅拷贝(shallow copy) 三.深拷贝(deep copy) 四.关于拷贝操作的警告 一.赋值 在python中,对象的赋值就是简单的对象引用,这点和C++不同.如下: a ...

  6. python浅拷贝 深拷贝

    Python 变量 对象 引用 1.变量 变量第一次赋值时被创建,变量在使用前必须赋值 变量本身没有类型,变量类型为它引用的对象类型: 变量在使用时被替换成它引用的对象 2.对象 对象本身具有计数和类 ...

  7. 【设计模式】原型模式 ( 浅拷贝 | 深拷贝 | 原型与单例冲突 | 禁用 final )

    文章目录 I . 原型模式 总结 II . 原型模式 浅拷贝 III . 原型模式 深拷贝 IV . 原型模式 与 单例 V . 原型模式 中的 final 关键字 ( 禁止出现 ) I . 原型模式 ...

  8. python 实例对象 浅拷贝_Python3 入门教程——浅拷贝深拷贝差别

    前言 在 Python 中提供了一个用于拷贝操作的 copy 模块,该模块中提供 浅拷贝 和 深拷贝 两种操作,其中: 浅拷贝:只是将对象管理地址进行打包复制,其内部的元素的并未进行复制,而是使用旧的 ...

  9. 【Python基础避坑】函数内存底层分析,全局变量/局部变量,参数传递,浅拷贝/深拷贝

    老高说,基本功不扎实会在工作中遇到很多的坑,非常同意- 函数定义示例 1.含有返回值 # -*-coding:utf-8-*- def add(a, b):'''两数相加'''sum = a + br ...

最新文章

  1. 九章算法【总结】Java 搞定链表-面试常考题目精选
  2. linux shell 算术运算{expr、bc、dc、(( ))和[ ]}
  3. FATE 集群部署 step2
  4. Ubuntu17.04安装WineQQ7.8及微信
  5. 详解python正则\b和\B的区别
  6. Linux 中复制文件到多个目录中
  7. jsoncpp 库的使用方法
  8. 大牛书单 | 数据库专题好书分享
  9. PHP Cookie和Session
  10. 一统江湖的大前端(2)—— Mock.js + Node.js 如何与后端潇洒分手
  11. html中select只读显示
  12. js 字符串转换成数字(转)
  13. Android系统搜索对话框(浮动搜索框)的使用
  14. linux 命令备份数据库,linux备份数据库命令
  15. python3.6 scrapy模块查询POS后台获取指定时间和状态的订单存入到excel表格中
  16. 哪个视频下载器好用呢?
  17. mysql 解压版安装教程
  18. 军犬舆情每日热点:强生爽身粉致癌案 被判赔偿47亿美元;华为正式进军电视行业
  19. eclipse写java private Date date 提示Date无法解析为类型
  20. Problem B. S03-03 银行利息(复利问题)

热门文章

  1. R语言 switch结构
  2. 基于无线EEG的脑机接口和新型干式传感器进行游戏控制
  3. linux trac apache,Ubuntu下集成Apache+Trac+Git
  4. Ubuntu16.04编译Android 6.0系统源码过程简要记录总结
  5. 【计算机原理与接口技术(UNIX)⑲ 完结篇】——可编程计数器 8254 [ 流光发生器、8254工作方式检测程序的设计]
  6. 康少带你玩转JavaScript
  7. 威尔特拉斯定理_数学大师启示录维尔斯特拉斯.pdf
  8. 计算机控制op是啥,安徽建筑大学 2015计算机控制技术 期末考试复习题
  9. 云服务器做网站详细,云服务器做网站
  10. 菜刀如何连接mysql_中国菜刀之终端操作及数据库管理