精华内容
下载资源
问答
  • 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:04
    Qt版文件或文件夹拷贝,将指定文件拷贝到指定位置,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
    拷贝构造函数 拷贝构造函数也是构造函数,长相和构造函数一样的,只是参数是固定 拷贝构造函数唯一的参数是对对象引用 不写拷贝构造函数,也存在一个默认的拷贝构造函数 拷贝构造函数作用: ...
  • 拷贝是一种高效的数据传输机制,在追求低延迟的传输场景中经常使用。 如果服务端要提供文件传输的功能,最简单的方式是: 1、将磁盘上的文件读取出来 2、通过网络协议将内容发送给客户端 传统IO的工作方式是 ...
  • C++ 浅拷贝 & 深拷贝

    千次阅读 多人点赞 2021-05-07 02:19:39
    C++ 对象的赋值, 赋值, 介绍浅拷贝 (shallow copy) 和深拷贝 (deep copy) 的区别.
  • C++浅拷贝与深拷贝

    千次阅读 2022-02-11 15:49:15
    拷贝:简单的赋值拷贝操作。 深拷贝:在堆区重新申请空间,进行拷贝操作。 C++中在对一个已知对象进行拷贝的时候,会调用类中的拷贝构造函数,如果程序员未定义拷贝构造函数,则会调用编译器默认的拷贝构造函数...
  • 拷贝和浅拷贝一、如何区分深拷贝和浅拷贝二、举例加深理解深拷贝和浅拷贝三、图文理解四、哪些方法是浅拷贝,如何进行深拷贝 一、如何区分深拷贝和浅拷贝 内在的区别:浅拷贝就是简单的把指向别人的值的一个指针...
  • 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:37
    Golang深拷贝拷贝 在了解原型设计模式之前我们需要新知道Golang的深拷贝与浅拷贝之间的区别。 推荐大家新看看Slice 和 Map那么常见的坑:https://blog.csdn.net/weixin_40165163/article/details/90707593 ...
  • 拷贝和浅拷贝

    千次阅读 2021-05-22 15:11:31
    对象拷贝指的就是将一个对象的所有属性(成员属性)拷贝到一个有着相同类型的对象中去 Java中的数据类型分为基本数据类习和引用数据类型,对于这两种数据类型,在进行赋值、用作方法参数、返回值的时候,会有值传递...
  • 秒懂深浅拷贝拷贝只是拷贝一层, 更深层次对象级别的只拷贝引用.【情形一】【情形二】【情形三】深拷贝拷贝多层, 每一级别的数据都会拷贝。深拷贝的实现(递归的方式) 浅拷贝只是拷贝一层, 更深层次对象级别的只...
  • 前端面试:浅拷贝和深拷贝的区别?

    万次阅读 多人点赞 2022-03-08 21:35:46
    拷贝(shallow copy):只复制指向某个对象的指针,而不复制对象本身,新旧对象共享一块内存;   深拷贝(deep copy):复制并创建一个一摸一样的对象,不共享内存,修改新对象,旧对象保持不变。
  • 【操作系统】:零拷贝

    千次阅读 2022-04-21 12:16:46
    所以拷贝以及零拷贝的学习势在必得,基于此,花了一段时间学习了拷贝和零拷贝。本文文字较多,需要耐心的阅读,当然后期笔者会补上一些示意图,辅助理解。本文主要尝试搞明白的问题有如下几个: 什么是拷贝? 什么...
  • 聊聊js的深拷贝与浅拷贝

    千次阅读 多人点赞 2020-09-02 22:57:27
    js 变量类型 js 的变量有两种类型的值 基本类型值 存放在栈中的一些简单的数据段 Undefined String Symbol(es6 新增) Null ...创建一个新对象,这个对象有着原始对象属性值得一份精确拷贝。如果属性是基本类型,
  • 拷贝:只拷贝源数据的第一层,修改拷贝的数据第一层,源数据也不会发生改变。修改拷贝的数据第二层源数据会发生改变。源数据的修改,拷贝的数据就会 深拷贝: 二、浅拷贝拷贝的实现方式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的深...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,903,055
精华内容 761,222
关键字:

拷贝