关于浅拷贝、深拷贝的探究
浅拷贝、深拷贝、完全拷贝
在这里介绍三个概念:
浅拷贝
:在拷贝操作时,对于被拷贝的对象的每一层拷贝都是指针拷贝。
深拷贝
:在拷贝操作时,对于被拷贝的对象至少有一层拷贝是对象拷贝。
完全拷贝
:在拷贝操作时,对于被拷贝的对象的每一层拷贝都是对象拷贝。
- 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.深拷贝赋值过程:输入数据→寄存器处理→开辟内存→写入数据。
一次深拷贝,可以得到被拷贝对象指针,并进行一次赋值操作。
对于深拷贝和完全拷贝, 下篇文章深拷贝和完全拷贝对比的探究会具体谈一谈.
关于浅拷贝、深拷贝的探究相关推荐
- Interview:算法岗位面试—10.11下午—上海某公司算法岗位(偏机器学习,互联网数字行业)技术面试考点之XGBoost的特点、python的可变不可变的数据类型、赋值浅拷贝深拷贝区别
ML岗位面试:10.11下午-上海某公司算法岗位(偏机器学习,互联网数字行业)技术面试考点之XGBoost的特点.python的可变不可变的数据类型.赋值浅拷贝深拷贝区别 Interview:算法岗位 ...
- 浅显易懂的浅拷贝深拷贝来了
1.基本数据类型,引用数据类型 说起深拷贝浅拷贝,必须先说数据类型.在拷贝数据的时候才能看出真正差异. 基本数据类型: string,number,boolean,undefined,null, 基本 ...
- Clone方法与浅拷贝深拷贝
Clone方法与浅拷贝&深拷贝 介绍 如何实现 浅拷贝 shallow copy 深拷贝 deep copy 数组中的clone 介绍 在Java中,如果需要创建一个对象的副本,特别是这个对象 ...
- 一文搞懂JS中的赋值·浅拷贝·深拷贝
前言 为什么写拷贝这篇文章?同事有一天提到了拷贝,他说赋值就是一种浅拷贝方式,另一个同事说赋值和浅拷贝并不相同.我也有些疑惑,于是我去MDN搜一下拷贝相关内容,发现并没有关于拷贝的实质概念,没有办法只 ...
- python3 赋值 浅拷贝 深拷贝 简介
目录 一.赋值 二.浅拷贝(shallow copy) 三.深拷贝(deep copy) 四.关于拷贝操作的警告 一.赋值 在python中,对象的赋值就是简单的对象引用,这点和C++不同.如下: a ...
- python浅拷贝 深拷贝
Python 变量 对象 引用 1.变量 变量第一次赋值时被创建,变量在使用前必须赋值 变量本身没有类型,变量类型为它引用的对象类型: 变量在使用时被替换成它引用的对象 2.对象 对象本身具有计数和类 ...
- 【设计模式】原型模式 ( 浅拷贝 | 深拷贝 | 原型与单例冲突 | 禁用 final )
文章目录 I . 原型模式 总结 II . 原型模式 浅拷贝 III . 原型模式 深拷贝 IV . 原型模式 与 单例 V . 原型模式 中的 final 关键字 ( 禁止出现 ) I . 原型模式 ...
- python 实例对象 浅拷贝_Python3 入门教程——浅拷贝深拷贝差别
前言 在 Python 中提供了一个用于拷贝操作的 copy 模块,该模块中提供 浅拷贝 和 深拷贝 两种操作,其中: 浅拷贝:只是将对象管理地址进行打包复制,其内部的元素的并未进行复制,而是使用旧的 ...
- 【Python基础避坑】函数内存底层分析,全局变量/局部变量,参数传递,浅拷贝/深拷贝
老高说,基本功不扎实会在工作中遇到很多的坑,非常同意- 函数定义示例 1.含有返回值 # -*-coding:utf-8-*- def add(a, b):'''两数相加'''sum = a + br ...
最新文章
- 九章算法【总结】Java 搞定链表-面试常考题目精选
- linux shell 算术运算{expr、bc、dc、(( ))和[ ]}
- FATE 集群部署 step2
- Ubuntu17.04安装WineQQ7.8及微信
- 详解python正则\b和\B的区别
- Linux 中复制文件到多个目录中
- jsoncpp 库的使用方法
- 大牛书单 | 数据库专题好书分享
- PHP Cookie和Session
- 一统江湖的大前端(2)—— Mock.js + Node.js 如何与后端潇洒分手
- html中select只读显示
- js 字符串转换成数字(转)
- Android系统搜索对话框(浮动搜索框)的使用
- linux 命令备份数据库,linux备份数据库命令
- python3.6 scrapy模块查询POS后台获取指定时间和状态的订单存入到excel表格中
- 哪个视频下载器好用呢?
- mysql 解压版安装教程
- 军犬舆情每日热点:强生爽身粉致癌案 被判赔偿47亿美元;华为正式进军电视行业
- eclipse写java private Date date 提示Date无法解析为类型
- Problem B. S03-03 银行利息(复利问题)
热门文章
- R语言 switch结构
- 基于无线EEG的脑机接口和新型干式传感器进行游戏控制
- linux trac apache,Ubuntu下集成Apache+Trac+Git
- Ubuntu16.04编译Android 6.0系统源码过程简要记录总结
- 【计算机原理与接口技术(UNIX)⑲ 完结篇】——可编程计数器 8254 [ 流光发生器、8254工作方式检测程序的设计]
- 康少带你玩转JavaScript
- 威尔特拉斯定理_数学大师启示录维尔斯特拉斯.pdf
- 计算机控制op是啥,安徽建筑大学 2015计算机控制技术 期末考试复习题
- 云服务器做网站详细,云服务器做网站
- 菜刀如何连接mysql_中国菜刀之终端操作及数据库管理