-
2021-07-31 16:50:00
文章目录
1、Python 深拷贝和浅拷贝概念理解
-
浅拷贝,指的是重新分配一块内存,创建一个新的对象,但里面的元素是原对象中各个子对象的引用。
-
深拷贝,是指重新分配一块内存,创建一个新的对象,并且将原对象中的元素,以递归的方式,通过创建新的子对象拷贝到新对象中。因此,新对象和原对象没有任何关联。
2、浅拷贝
- 使用数据类型本身的构造器
- 对于可变的序列,还可以通过切片操作符 : 来完成浅拷贝
- Python 还提供了对应的函数 copy.copy() 函数,适用于任何数据类型
2.1 使用数据类型本身的构造器
list1 = [1, 2, 3] list2 = list(list1) print(list2) print("list1==list2 ?",list1==list2) print("list1 is list2 ?",list1 is list2) set1= set([1, 2, 3]) set2 = set(set1) print(set2) print("set1==set2 ?",set1==set2) print("set1 is set2 ?",set1 is set2) dict1 = {1:[1,'w'], 2:0, 3:98} dict2 = dict(dict1) print(dict2) print("dict1 == dict2 ?",dict1 == dict2) print("dict1 is dict2 ?",dict1 is dict2) [1, 2, 3] list1==list2 ? True list1 is list2 ? False {1, 2, 3} set1==set2 ? True set1 is set2 ? False {1: [1, 'w'], 2: 0, 3: 98} dict1 == dict2 ? True dict1 is dict2 ? False
分析: 浅拷贝,为新变量重新分配一块内存,和原来变量的内存不一样,所以有
list1 is list2 ? False set1 is set2 ? False dict1 is dict2 ? False
但浅拷贝完,两个变量中的元素的值是一样的。
list1==list2 ? True dict1 == dict2 ? True set1==set2 ? True
2.2 对于列表
对于列表,还可以通过切片操作符“:”来完成浅拷贝
list1 = [1, 2, 3] list2 = list1[:] print(list2) print("list1 == list2 ?",list1 == list2) print("list1 is list2 ?",list1 is list2) [1, 2, 3] list1 == list2 ? True list1 is list2 ? False
2.3 使用 copy.copy() 函数
函数 copy.copy() 函数,适用于任何数据类型
import copy list1 = [1, 2, 3] list2 = copy.copy(list1) print(list2) print("list1 == list2 ?",list1 == list2) print("list1 is list2 ?",list1 is list2) set1 = {1, 2, 3} set2 = copy.copy(set1) print(set2) print("set1 == set2 ?",set1 == set2) print("set1 is set2 ?",set1 is set2) dict1 = {1:'xiaoming', 2:'xiahua',3:'xiaoli'} dict2 = dict(dict1) print(dict2) print("dict1 == dict2 ?",dict1 == dict2) print("dict1 is dict2 ?",dict1 is dict2) [1, 2, 3] list1 == list2 ? True list1 is list2 ? False {1, 2, 3} set1 == set2 ? True set1 is set2 ? False {1: 'xiaoming', 2: 'xiahua', 3: 'xiaoli'} dict1 == dict2 ? True dict1 is dict2 ? False
2.4 对于元组
对于元组,使用 tuple() 或者切片操作符 ‘:’ 不会创建一份浅拷贝,相反它会返回一个指向相同元组的引用:
tuple1 = (1, 2, 3) tuple2 = tuple(tuple1) print(tuple2) print("tuple1 == tuple2 ?",tuple1 == tuple2) print("tuple1 is tuple2 ?",tuple1 is tuple2) tuple1 = (1, 2, 3) tuple2 = tuple1[:] print(tuple2) print("tuple1 == tuple2 ?",tuple1 == tuple2) print("tuple1 is tuple2 ?",tuple1 is tuple2) (1, 2, 3) tuple1 == tuple2 ? True tuple1 is tuple2 ? True (1, 2, 3) tuple1 == tuple2 ? True tuple1 is tuple2 ? True
使用 tuple() 或者切片操作符 ‘:’ 不会创建一份浅拷贝,因为它开辟新的内存存储的是原对象的引用,而没有创建新的对象来存储原对象的子对象的引用,所以不是浅拷贝。相反它会返回一个指向相同元组的引用。
对字符串使用 str() 或者切片操作符 ‘:’,原理和 元组相同。
str1 = 'operation' str2 = str1[:] print(str2) print("str1 == str2 ?",str1 == str2) print("str1 is str2 ?",str1 is str2) operation str1 == str2 ? True str1 is str2 ? True
str1 = 'operation' str2 = str(str1) print(str2) print("str1 == str2 ?",str1 == str2) print("str1 is str2 ?",str1 is str2) operation str1 == str2 ? True str1 is str2 ? True
import copy set1 = (1, 2, 3) set2 = copy.copy(set1) print(set2) print("set1 == set2 ?",set1 == set2) print("set1 is set2 ?",set1 is set2) (1, 2, 3) set1 == set2 ? True set1 is set2 ? True
import copy set1 = 'operation' set2 = copy.copy(set1) print(set2) print("set1 == set2 ?",set1 == set2) print("set1 is set2 ?",set1 is set2) operation set1 == set2 ? True set1 is set2 ? True
也就是说,对字符串和元组使用 copy()、[:]、本身的构造器完成的复制,都只是开辟了内存存储原对象的引用,而不是存储原对象的子对象的引用。
2.5 关于切片操作符 ‘:’
切片操作符 ‘:’ 不能用于字典和集合完成浅拷贝
# set1 = {1, 2, 3} # set2 = set1[:] # dict1 = {1:1, 2:2, 3:3} # dict2 = dict1[:]
2.6 和赋值的区别
和赋值的本质区别在于,赋值只是把原对象的引用给到新对象
set1 = {1:1, 2:2, 3:3} set2 = set1 print(set2) print("set1 == set2 ?",set1 == set2) print(id(set1)) print(id(set2)) {1: 1, 2: 2, 3: 3} set1 == set2 ? True 2515252654368 2515252654368
2.7 浅拷贝需注意的问题
对数据采用浅拷贝的方式时,如果原对象中的元素不可变,那倒无所谓;但如果元素可变,浅拷贝通常会出现一些问题,
list1 = [[1, 2], (30, 40)] list2 = list(list1) list1.append(100) print("list1:",list1) print("list2:",list2) list1[0].append(3) print("list1:",list1) print("list2:",list2) list1[1] += (50, 60) print("list1:",list1) print("list2:",list2) list1: [[1, 2], (30, 40), 100] list2: [[1, 2], (30, 40)] list1: [[1, 2, 3], (30, 40), 100] list2: [[1, 2, 3], (30, 40)] list1: [[1, 2, 3], (30, 40, 50, 60), 100] list2: [[1, 2, 3], (30, 40)]
2、深拷贝
Python 中以 copy.deepcopy() 来实现对象的深度拷贝
import copy list1 = [[1, 2], (30, 40)] list2 = copy.deepcopy(list1) list1.append(100) print("list1:",list1) print("list2:",list2) list1[0].append(3) print("list1:",list1) print("list2:",list2) list1[1] += (50, 60) print("list1:",list1) print("list2:",list2) list1: [[1, 2], (30, 40), 100] list2: [[1, 2], (30, 40)] list1: [[1, 2, 3], (30, 40), 100] list2: [[1, 2], (30, 40)] list1: [[1, 2, 3], (30, 40, 50, 60), 100] list2: [[1, 2], (30, 40)]
更多相关内容 -
-
Qt文件或文件夹拷贝
2019-01-09 15:39:04Qt版文件或文件夹拷贝,将指定文件拷贝到指定位置,copyFileToPath拷贝文件copyDirectoryFiles拷贝文件夹 -
C++之深拷贝和浅拷贝
2015-09-09 19:06:07通过简短的代码和图片来说明C++中深拷贝和浅拷贝的区别和概念。 -
面试题:深拷贝和浅拷贝(超级详细,有内存图)
2019-08-07 13:07:34深拷贝和浅拷贝是经常在面试中会出现的,主要考察你对基本类型和引用类型的理解深度。我在无数次的面试中,应聘者还没有一个人能把这个问题回答情况,包括很多机构的培训老师。这篇文章会让你把基本类型和引用类型...这篇文章竟然写了一上午,亲,请怀着感恩的心阅读!!
深拷贝和浅拷贝是经常在面试中会出现的,主要考察你对基本类型和引用类型的理解深度。我在无数次的面试中,应聘者还没有一个人能把这个问题回答情况,包括很多机构的培训老师。这篇文章会让你把基本类型和引用类型的区别搞得清清楚楚,搞清楚这两者的区别,你对任何编程语言的都不怕,因为,这不是js一门语言,是任何编程语言中都需要掌握的知识,而且,在任何编程语言中,两者都是一样的。
深拷贝和浅拷贝主要是针对对象的属性是对象(引用类型)
一、基本类型和引用类型的区别
1、先了解内存
任何编程语言的内存分区几乎都是一样的
内存是存储数据的,不同类型的数据要存储在不同的区域,即分类存放,不同的区域作用和功能也不一样。就像你家里的衣柜一样,也分了不同的区域:如挂西装的区域,放袜子的区域等等,我相信每个人都会把这两个东西放在不同的区域。要不然,当你西装革履地参加一个高档的宴会,手塞在裤兜里,掏出来一只臭袜子,是不是很尴尬!!!哈哈!!!
以下为内存的分区图。内存分为四个区域:栈区(堆栈),堆区,全局静态区,只读区(常量区和代码区)。
https://blog.csdn.net/jiang7701037/article/details/98728249
2、基本类型和引用类型在内存上存储的区别
现在只看栈区和堆区,不管其它区域,也假定只是局部变量。
以上函数testf在调用时,
1)、 定义局部变量 age,由于age是局部变量,所以在栈中申请内存空间,起名为age,又由于给age赋的值250是基本类型,所以,值直接存储在栈中。
2)、定义局部变量arr,由于arr是局部变量,所以在栈中申请空间,但是arr的内存中存储的是什么?由于给arr赋的值不是基本类型,而是引用类型(new出来的),所以,先在堆中申请空间存放数据 12,23,34,。再把堆区的地址赋给arr。
3、到底什么是基本类型和引用类型
1)、基本类型:就是值类型,即在变量所对应的内存区域存储的是值,如:上面的age变量所对应的内存存储的就是值250.
2)、引用类型:就是地址类型。
何为地址:地址就是编号,要地址何用,就是为了容易找到。每个人的家里为什么要有一个唯一的地址,就是在邮寄时,能够找到你家。
比如:我们最早的超市存包的格子,每个格子都有个编号,你存包时,服务员会把你的东西放在某个格子里,再把这个格子的编号给你(一个牌子)。你购物完毕取包时,直接给服务员你的牌子(有编号),服务员根据你的编号就会找到你的包。这个编号就是格子的地址。内存也是一样的,每个内存都有一个编号,方便cpu查找。要不然,浩瀚的内存海洋,cpu要找到数据靠啥找。
以上的变量arr就是引用类型,arr所对应的内存中存储着地址,真正的数据是在地址对应的内存区域里,就像,你填写简历时,会在简历的那张纸上写上你家的地址。简历上写你家地址的地方就相当于arr。而你家是根据这个地址可以找到的。简历上写你家地址的地方就相当于引用着你家(可以想象一根无形的线牵引着你家,在简历上的这根无形的线,顺藤摸瓜就能找到你家)。所以叫做引用类型。
二、基本类型和引用类型在赋值时内存的变化
你可以认为,赋值就是在拷贝。
1、基本类型:
2、引用类型:
如果给arr[0]赋值的话,arr1[0]的值也会发生变化,因为,arr和arr1保存着相同的地址,它门两个引用的数据是共享的。就像你在很多地方(简历的那张纸,户口本上的那张纸)会写上你的家庭地址。这么多张纸都引用着你家。根据一张纸上找到你家,给你家放上一百万的现金(数据改变了,相当于arr[0]=10),再根据另外一张纸的地址也找到了你家,你发现你一百万在(不要给我说被人拿了)
如果在上面的基础上增加一句代码:arr[0]=10;那么内存将会有如下变化:
三、基本类型和引用类型作为函数参数的区别(这个可以不看)
1、基本类型作为函数的参数
2、引用类型作为函数的参数:
四、深拷贝和浅拷贝:
终于说到了深拷贝和浅拷贝。
其实在第二点已经说到了拷贝,所谓拷贝,就是赋值。把一个变量赋给另外一个变量,就是把变量的内容进行拷贝。把一个对象的值赋给另外一个对象,就是把一个对象拷贝一份。
1、基本类没有问题,
因为,基本类型赋值时,赋的是数据(所以,不存在深拷贝和浅拷贝的问题)。
如:
Var x = 100;
Var y = x; //此时x和y都是100;
如果要改变y的值,x的值不会改变。
2、引用类型有问题
因为,引用类型赋值时,赋的值地址(就是引用类型变量在内存中保存的内容),强烈建议把前面的第二点(基本类型和引用类型在赋值时内存的变化)多看几遍,以保证理解深刻。这样,一劳永逸,以后在碰到任何跟引用类型有关的话题(如:继承时,父类的属性是引用类型)都没有问题。
如:
var arr1 = new Array(12,23,34)
Var arr2 = arr1;//这就是一个最简单的浅拷贝
如果要改变arr2所引用的数据:arr2[0]=100时,那么arr1[0]的值也是100。
原因就是 arr1和arr2引用了同一块内存区域(以上的第二点中有体现)。
这是最简单的浅拷贝,因为,只是把arr1的地址拷贝的一份给了arr2,并没有把arr1的数据拷贝一份。所以,拷贝的深度不够
3、用json对象的方式(也是引用类型)来演示浅拷贝和深拷贝
1)、定义一个json对象(对象的属性也是对象)
var p = { "id":"007", "name":"刘德华", "books":new Array("三国演义","红楼梦","水浒传")//这是引用类型 }
内存图:
2)、把该对象p进行复制一份
- (一)浅拷贝
var p2 = {}; for(let key in p){ p2[key] = p[key]; } p2.books[0] ="四国"; console.log(p2); console.log(p);
在控制台中打印的结果(p和p2的books[0]都变成了“四国”):
内存:
- (二)深拷贝(初步)
var p2 = {}; for(let key in p){ if(typeof p[key]=='object'){ p2[key]=[];//因为,我上面写的是数组,所以,暂时赋值一个空数组. for(let i in p[key]){ p2[key][i] = p[key][i] } }else{ p2[key] = p[key]; } } p2.books[0] ="四国"; console.log(p2); console.log(p);
在控制台中打印的结果(只有p2的books[0]变成了“四国”)
内存:
(三)深拷贝(最终)
3.1、深拷贝_如果属性都是json对象,那么用递归的方式
//如果对象的属性是对象(引用类型),属性的属性也是引用类型,即层层嵌套很多.怎么办,只能递归
//如下对象,要复制:
var p = { "id":"007", "name":"刘德华", "wife":{ "id":"008", "name":"刘德的妻子", "address":{ "city":"北京", "area":"海淀区" } } } //写函数 function copyObj(obj){ let newObj={}; for(let key in obj){ if(typeof obj[key] =='object'){//如:key是wife,引用类型,那就递归 newObj[key] = copyObj(obj[key]) }else{//基本类型,直接赋值 newObj[key] = obj[key]; } } return newObj; } let pNew = copyObj(p); pNew.wife.name="张三疯"; pNew.wife.address.city = "香港"; console.log(pNew); console.log(p);
3.2、深拷贝_如果属性是数组等非键值对的对象
就得单独处理:要么给数组增加一个自我复制的函数(建议这样做),要么单独判断。
//给数组对象增加一个方法,用来复制自己 Array.prototype.copyself = function(){ let arr = new Array(); for(let i in this){ arr[i] = this[i] } return arr; } var p = { "id":"007", "name":"刘德华", "books":new Array("三国演义","红楼梦","水浒传")//这是引用类型 } function copyObj(obj){ let newObj={}; for(let key in obj){ if(typeof obj[key] =='object'){//如:key是wife,引用类型,那就递归 newObj[key] = obj[key].copyself(); }else{//基本类型,直接赋值 newObj[key] = obj[key]; } } return newObj; } var pNew = copyObj(p); pNew.books[0] = "四国"; console.log(pNew); console.log(p);
这篇文章竟然写了一上午,亲,请怀着感恩的心阅读
-
深拷贝和浅拷贝的区别
2021-08-16 19:38:36首先,明确一点深拷贝和浅拷贝是针对对象属性为对象的,因为基本数据类型在进行赋值操作时(也就是拷贝)是直接将值赋给了新的变量,也就是该变量是原变量的一个副本,这个时候你修改两者中的任何一个的值都不会影响...首先,明确一点深拷贝和浅拷贝是针对对象属性为对象的,因为基本数据类型在进行赋值操作时(也就是拷贝)是直接将值赋给了新的变量,也就是该变量是原变量的一个副本,这个时候你修改两者中的任何一个的值都不会影响另一个,而对于对象或者引用数据来说在进行浅拷贝时,只是将对象的引用复制了一份,也就内存地址,即两个不同的变量指向了同一个内存地址,那么在改变任一个变量的值都是该变这个内存地址的所存储的值,所以两个变量的值都会改变。
一、clone()方法
在Java中是用clone()方法实现深拷贝的,比如以下代码在Java中是很常见的
Person p = new Person(23, "zhang"); Person p1 = p; System.out.println(p); System.out.println(p1);
这段代码的打印结果为:
testclone.Person@2f9ee1ac
testclone.Person@2f9ee1ac可以看出两者打印的地址是相同的,既然地址相同那就代表两者是同一个对象,而p和p1都只是引用罢了。代码执行后,内存中的情况
而下面这段代码才是真的克隆了一个对象
Person p = new Person(23, "zhang"); Person p1 = (Person) p.clone(); System.out.println(p); System.out.println(p1)
打印的结果为:
testclone.Person@2f9ee1ac
testclone.Person@67f1fba0从结果来看两者不是同一个地址,那自然就不是同一个对象,而内存情况如下
二、深拷贝和浅拷贝
在上面的代码中Person中有两个成员变量,分别是name和age, name是String类型, age是int类型。代码非常简单,如下所示:
public class Person implements Cloneable{ private int age ; private String name; public Person(int age, String name) { this.age = age; this.name = name; } public Person() {} public int getAge() { return age; } public String getName() { return name; } @Override protected Object clone() throws CloneNotSupportedException { return (Person)super.clone(); } }
Person类的两个成员变量中,age是基本数据类型,关于基本数据类型的拷贝在上面就已经说过了,但是name是引用数据类型,它只是一个引用, 指向一个真正的String对象,那么对它的拷贝有两种方式: 直接将源对象中的name的引用值拷贝给新对象的name字段, 或者是根据原Person对象中的name指向的字符串对象创建一个新的相同的字符串对象,将这个新字符串对象的引用赋给新拷贝的Person对象的name字段。这两种拷贝方式分别叫做浅拷贝和深拷贝。深拷贝和浅拷贝的原理如下图所示:
下面我们通过代码来验证:如果两个Person对象的name的地址值相同, 说明两个对象的name都指向同一个String对象, 也就是浅拷贝, 而如果两个对象的name的地址值不同, 那么就说明指向不同的String对象, 也就是在拷贝Person对象的时候, 同时拷贝了name引用的String对象, 也就是深拷贝。验证代码如下:
Person p = new Person(23, "zhang"); Person p1 = (Person) p.clone(); String result = p.getName() == p1.getName() ? "clone是浅拷贝的" : "clone是深拷贝的"; System.out.println(result);
打印的结果为:
clone是浅拷贝
也就是clone方法本身是一个浅拷贝的方法,而上一个代码我们又得出clone是深拷贝,那么是我前面写错了吗?那当然不是,clone方法本身是浅拷贝的,但是我们可以通过重写该方法来实现深拷贝 ,所以要实现深拷贝我们就需要实现Cloneable接口,覆盖并实现clone方法,除了调用父类中的clone方法得到新的对象, 还要将该类中的引用变量也clone出来。如果只是用Object中默认的clone方法,是浅拷贝的,再次以下面的代码验证:
static class Body implements Cloneable{ public Head head; public Body() {} public Body(Head head) {this.head = head;} @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } static class Head /*implements Cloneable*/{ public Face face; public Head() {} public Head(Face face){this.face = face;} } public static void main(String[] args) throws CloneNotSupportedException { Body body = new Body(new Head()); Body body1 = (Body) body.clone(); System.out.println("body == body1 : " + (body == body1) ); System.out.println("body.head == body1.head : " + (body.head == body1.head)); }
在上述代码中有两个主要的类,Body和Face,Body类中又组合了Face对象,在对Body进行clone时,它所组合的Face对象时浅拷贝,其打印结果可以很好的证明这一点:
body == body1 : false
body.head == body1.head : true如果要使Body对象在clone时进行深拷贝, 那么就要在Body的clone方法中,将源对象引用的Head对象也clone一份。
static class Body implements Cloneable{ public Head head; public Body() {} public Body(Head head) {this.head = head;} @Override protected Object clone() throws CloneNotSupportedException { Body newBody = (Body) super.clone(); newBody.head = (Head) head.clone(); return newBody; } } static class Head implements Cloneable{ public Face face; public Head() {} public Head(Face face){this.face = face;} @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } public static void main(String[] args) throws CloneNotSupportedException { Body body = new Body(new Head()); Body body1 = (Body) body.clone(); System.out.println("body == body1 : " + (body == body1) ); System.out.println("body.head == body1.head : " + (body.head == body1.head)); }
打印结果为:
body == body1 : false
body.head == body1.head : false由此可见, body和body1内的head引用指向了不同的Head对象, 也就是说在clone Body对象的同时, 也拷贝了它所引用的Head对象, 进行了深拷贝。
从以上的内容中我们可以知道,一个对象要实现深拷贝,就要实现Cloneable接口,重写clone()方法,并在clone()方法中将对象引用的其他对象也要clone一份,这就要求被引用的对象也要实现Cloneable接口,并实现clone()方法。而按照这个结论,Body类中组合了Head类,而Head类中又组合了Face类,在对Body对象进行深拷贝时,会拷贝其中的Head类,而这时默认执行的时浅拷贝,也就是说其中的Face对象并不会被拷贝,代码如下:
static class Body implements Cloneable{ public Head head; public Body() {} public Body(Head head) {this.head = head;} @Override protected Object clone() throws CloneNotSupportedException { Body newBody = (Body) super.clone(); newBody.head = (Head) head.clone(); return newBody; } } static class Head implements Cloneable{ public Face face; public Head() {} public Head(Face face){this.face = face;} @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } static class Face{} public static void main(String[] args) throws CloneNotSupportedException { Body body = new Body(new Head(new Face())); Body body1 = (Body) body.clone(); System.out.println("body == body1 : " + (body == body1) ); System.out.println("body.head == body1.head : " + (body.head == body1.head)); System.out.println("body.head.face == body1.head.face : " + (body.head.face == body1.head.face)); }
打印结果为:
body == body1 : false
body.head == body1.head : false
body.head.face == body1.head.face : true那我们可以想一想,这对Body对象来说,到底是不是深拷贝,其实是可以算的,因为Body对象中的引用对象是拷贝了的(这段代码中只有Head对象的引用),也就是说两个独立的Body对象中的Head引用指向了两个独立的Head对象,但对于Head对象来说,其Face引用指向了同一个Face对象。所以严格来说这是一种不彻底的深拷贝,而若是想要彻底的深拷贝,就要保证该对象的所有引用对象的类型都要去实现Cloneable接口,实现clone方法。
参考文献:https://blog.csdn.net/zhangjg_blog/article/details/18369201
-
浅谈深拷贝和浅拷贝
2020-12-30 10:05:20深拷贝和浅拷贝说起深拷贝和浅拷贝,首先我们来看两个栗子// 栗子1var a = 1,b=a;console.log(a);console.log(b)b = 2;console.log(a);console.log(b)// 栗子2var obj1 = {x: 1, y: 2}, obj2 = obj1;console.log(obj...深拷贝和浅拷贝
说起深拷贝和浅拷贝,首先我们来看两个栗子
// 栗子1
var a = 1,b=a;
console.log(a);
console.log(b)
b = 2;
console.log(a);
console.log(b)
// 栗子2
var obj1 = {x: 1, y: 2}, obj2 = obj1;
console.log(obj1) //{x: 1, y: 2}
console.log(obj2) //{x: 1, y: 2}
obj2.x = 2; //修改obj2.x
console.log(obj1) //{x: 2, y: 2}
console.log(obj2) //{x: 2, y: 2}
按照惯性思维,栗子1中obj1应该跟a一样,不会因另外一个值的改变而改变的啊,而这里却是obj1跟着obj2的改变而改变了?同样都是变量,怎么就表现不一样了呢?难道存在等级上的优劣?此处需要沉思一小会。要解决这个问题,就要引入一个JS中基本类型和引用类型的概念了。
基本类型和引用类型
ECMAScript变量包含两种不同数据类型的值:基本类型值和引用类型值。基本类型值指的是那些保存在栈内存中的简单数据段,即这种值完全保存在内存中的一个位置。而引用类型值是指那些保存堆内存中的对象,意思是变量中保存的实际上只是一个指针,这个指针指向内存中的另一个位置,该位置保存对象。
两类数据的保存方式
从上图可以看到,栈内存主要用于存
-
详细讲解js中的深拷贝与浅拷贝
2021-09-05 20:53:02深拷贝 JSON.parse(JSON.stringify(obj))深拷贝已有对象 JSON.stingify(obj)将js中的对象转换成JSON字符串 let jack = { name: 'jack' } console.log(jack) console.log(JSON.stringify(jack)) 它们在格式上有... -
Java深入理解深拷贝和浅拷贝区别
2019-02-13 23:31:47一、拷贝的引入 (1)、引用拷贝 创建一个指向对象的引用变量的拷贝。 Teacher teacher = new Teacher("Taylor",26); Teacher otherteacher = teacher; System.out.println(teacher); System.out.println... -
什么是零拷贝
2022-03-24 16:37:49零拷贝是老生常谈的问题,无论是Kafka还是Netty等都用到了零拷贝的知识,那究竟什么是零拷贝呢 什么是零拷贝 “零”:表示次数是0,它表示拷贝数据的次数是0 -
详解JS深拷贝与浅拷贝
2022-04-10 14:50:11深拷贝与浅拷贝 深拷贝和浅拷贝都只针对引用数据类型,浅拷贝会对对象逐个成员依次拷贝,但只复制内存地址,而不复制对象本身,新旧对象成员还是共享同一内存;深拷贝会另外创建一个一模一样的对象,新对象跟原对象... -
Java IO篇:什么是零拷贝?
2022-01-24 02:06:05零拷贝指在进行数据 IO 或传输时,数据在用户态下经历了零次拷贝,并非不拷贝数据。通过减少数据传输过程中 内核缓冲区和用户进程缓冲区间不必要的 CPU数据拷贝 与 用户态和内核态的上下文切换次数,降低 CPU 在这两... -
一文了解Python深拷贝与浅拷贝问题
2019-03-01 12:36:29在平时工作中,经常涉及到数据的传递,在数据传递使用过程中,可能会发生数据被修改的问题。...今天就说一下Python中的深拷贝与浅拷贝的问题。 概念普及:对象、可变类型、引用 数据拷贝会涉... -
python篇 深拷贝与浅拷贝
2021-12-09 14:30:42深拷贝浅拷贝有点类似于这个,“浅”字在这里的意思就是浅浅一层,仅能能拷贝对象的表层,而其子对象,就是直接拿来引用了,所谓深拷贝就是用递归的原理把其子对象也依次拷贝下来,这就是两者的区别。 -
c++拷贝函数——深浅拷贝
2022-03-19 22:32:01拷贝构造函数 拷贝构造函数也是构造函数,长相和构造函数一样的,只是参数是固定 拷贝构造函数唯一的参数是对对象引用 不写拷贝构造函数,也存在一个默认的拷贝构造函数 拷贝构造函数作用: ... -
零拷贝机制在文件传输中的使用手法
2022-02-23 23:24:35零拷贝是一种高效的数据传输机制,在追求低延迟的传输场景中经常使用。 如果服务端要提供文件传输的功能,最简单的方式是: 1、将磁盘上的文件读取出来 2、通过网络协议将内容发送给客户端 传统IO的工作方式是 ... -
C++ 浅拷贝 & 深拷贝
2021-05-07 02:19:39C++ 对象的赋值, 赋值, 介绍浅拷贝 (shallow copy) 和深拷贝 (deep copy) 的区别. -
C++浅拷贝与深拷贝
2022-02-11 15:49:15浅拷贝:简单的赋值拷贝操作。 深拷贝:在堆区重新申请空间,进行拷贝操作。 C++中在对一个已知对象进行拷贝的时候,会调用类中的拷贝构造函数,如果程序员未定义拷贝构造函数,则会调用编译器默认的拷贝构造函数... -
详解深拷贝和浅拷贝以及如何深拷贝
2020-09-10 10:50:17深拷贝和浅拷贝一、如何区分深拷贝和浅拷贝二、举例加深理解深拷贝和浅拷贝三、图文理解四、哪些方法是浅拷贝,如何进行深拷贝 一、如何区分深拷贝和浅拷贝 内在的区别:浅拷贝就是简单的把指向别人的值的一个指针... -
golang浅拷贝与深拷贝
2021-04-11 14:37:37浅拷贝 golang中通过copy方法,可以实现浅拷贝操作。 func copy(dst, src []Type) int 基本认识: 1.copy只能用于切片,不能用于 map 等任何其他类型。 2.copy返回结果为一个 int 型值,表示 copy 从原切片src复制... -
Golang深拷贝浅拷贝
2019-05-30 23:19:37Golang深拷贝浅拷贝 在了解原型设计模式之前我们需要新知道Golang的深拷贝与浅拷贝之间的区别。 推荐大家新看看Slice 和 Map那么常见的坑:https://blog.csdn.net/weixin_40165163/article/details/90707593 ... -
深拷贝和浅拷贝
2021-05-22 15:11:31对象拷贝指的就是将一个对象的所有属性(成员属性)拷贝到一个有着相同类型的对象中去 Java中的数据类型分为基本数据类习和引用数据类型,对于这两种数据类型,在进行赋值、用作方法参数、返回值的时候,会有值传递... -
教你如何识别和实现深拷贝与浅拷贝
2021-01-08 15:38:45秒懂深浅拷贝浅拷贝只是拷贝一层, 更深层次对象级别的只拷贝引用.【情形一】【情形二】【情形三】深拷贝拷贝多层, 每一级别的数据都会拷贝。深拷贝的实现(递归的方式) 浅拷贝只是拷贝一层, 更深层次对象级别的只... -
前端面试:浅拷贝和深拷贝的区别?
2022-03-08 21:35:46浅拷贝(shallow copy):只复制指向某个对象的指针,而不复制对象本身,新旧对象共享一块内存; 深拷贝(deep copy):复制并创建一个一摸一样的对象,不共享内存,修改新对象,旧对象保持不变。 -
【操作系统】:零拷贝
2022-04-21 12:16:46所以拷贝以及零拷贝的学习势在必得,基于此,花了一段时间学习了拷贝和零拷贝。本文文字较多,需要耐心的阅读,当然后期笔者会补上一些示意图,辅助理解。本文主要尝试搞明白的问题有如下几个: 什么是拷贝? 什么... -
聊聊js的深拷贝与浅拷贝
2020-09-02 22:57:27js 变量类型 js 的变量有两种类型的值 基本类型值 存放在栈中的一些简单的数据段 Undefined String Symbol(es6 新增) Null ...创建一个新对象,这个对象有着原始对象属性值得一份精确拷贝。如果属性是基本类型, -
【web前端面试必问7】浅拷贝和深拷贝
2022-04-09 11:50:27浅拷贝:只拷贝源数据的第一层,修改拷贝的数据第一层,源数据也不会发生改变。修改拷贝的数据第二层源数据会发生改变。源数据的修改,拷贝的数据就会 深拷贝: 二、浅拷贝 浅拷贝的实现方式1 直接上案例分析... -
Python3的深拷贝与浅拷贝
2021-12-08 22:16:33在理解深拷贝和前拷贝之前,首先要了解python的可变类型和不可变类型: 可变类型:list、dict 不可变类型:number、str、bool、tuple python中的不可变数据类型,不允许变量的值 原地 发生变化,一但值发生了变化... -
深拷贝和浅拷贝的区别和与原理
2020-05-25 16:52:49二、浅拷贝和深拷贝 如图所示: obj2是对obj1的浅拷贝,obj2新建了一个对象,但是obj2对象复制的是obj1的指针,也就是obj1的堆内存地址,而不是复制对象本身。obj1和obj2是共用了内存地址的。 obj3是对obj1的深...