首页 > 其他分享 >引用拷贝和浅拷贝和深拷贝

引用拷贝和浅拷贝和深拷贝

时间:2024-07-29 14:54:27浏览次数:10  
标签:对象 clone 嵌套 地址 引用 拷贝 序列化

引用拷贝
定义:

引用拷贝只复制对象的地址值,不会创建新的对象,改变拷贝对象的属性,原对象属性也会发生变化

实现方式

通常是"="直接赋值,

浅拷贝:
定义

浅拷贝会创建新的对象接收,所以改变拷贝对象的属性时不会影响源对象,但是浅拷贝不会创建内部嵌套对象,而是引用嵌套对象地址,所以如果嵌套对象属性发生改变,都会发生改变。

(备注:如果有嵌套多层对象也是拷贝引用地址因为只需拷贝最外面的嵌套对象就拷贝了里面对象的地址)

实现方式

1.jdk:被拷贝的对象实现了 Cloneable 接口,并且重写了 clone() 方法

class Person implements Cloneable {
	// ...变量属性
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone(); // 使用Object类的clone()方法进行浅拷贝
    }
}

2.工具类库:

hutool的ObjectUtils.clone()方法即是浅克隆也是深克隆,如果类实现了Cloneable接口就是浅克隆,如果只实现了Serializable接口就是深克隆,原理是序列化和反序列化

hutool的 BeanUtil.copyProperties()方法也是浅拷贝

深拷贝:
定义

深拷贝会递归地复制对象及其内部的所有嵌套对象,创建一个完全独立的副本与原始对象之间完全独立,对其中一个的修改都不会影响另一个

实现方式

1.实现序列化接口,通过对象的序列化和反序列化可以实现深拷贝。或是通过第三方工具类库原理是一样的比如hutool的ObjectUtils.clone()方法即是浅克隆也是深克隆,如果类实现了Cloneable接口就是浅克隆,如果只实现了Serializable接口就是深克隆,代码见测试用例

 public static <T> T clone(T obj) {
        T result = ArrayUtil.clone(obj);
        if (null == result) {
            if (obj instanceof Cloneable) {
                result = ReflectUtil.invoke(obj, "clone", new Object[0]);
            } else {
                result = cloneByStream(obj);
            }
        }

        return result;
    }

2.递归复制,不管用谁的克隆方法主要是要自己写递归的逻辑

测试用例
 @Test
    public void copyTest() throws CloneNotSupportedException {
        CopyTest copyTest = new CopyTest();
        copyTest.setTrader(new Trader("Bob","cd"));
        CopyTest copyTest2 = (CopyTest)copyTest.clone();
        copyTest2.getTrader().setName("newname");
        log.info("源对象地址:{} 源嵌套对象地址:{}, {}",copyTest,copyTest.getTrader(), copyTest.getTrader().getName());
        log.info("jdk.clone对象地址:{} 嵌套对象地址:{}, {}",copyTest2,copyTest2.getTrader(),  copyTest2.getTrader().getName());

        CopyTest copyTest3 = ObjectUtil.clone(copyTest);
        log.info("ObjectUtil.clone对象地址:{} 嵌套对象地址:{}",copyTest3,copyTest3.getTrader());

        CopyTest copyTest4 = new CopyTest();
        DataConverterUtil.copyProperties(copyTest,copyTest4);
        log.info("cglib.copy对象地址:{} 嵌套对象地址:{}",copyTest4,copyTest4.getTrader());

    	// 深拷贝
 		// 将对象序列化为字节流
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(bos);
        out.writeObject(copyTest);
        // 反序列化为新对象
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream in = new ObjectInputStream(bis);
        CopyTest copyTest5 = (CopyTest)in.readObject();
        log.info("序列化反序列化对象地址:{} 嵌套对象地址:{}",copyTest5,copyTest5.getTrader());
    }

打印结果:
 浅拷贝:源对象地址:com.wrx.king.entity.CopyTest@309e345f 源嵌套对象地址:com.wrx.king.entity.Trader@56a6d5a6, newname
 浅拷贝:jdk.clone对象地址:com.wrx.king.entity.CopyTest@71b1176b 嵌套对象地址:com.wrx.king.entity.Trader@56a6d5a6, newname
 浅拷贝:ObjectUtil.clone对象地址:com.wrx.king.entity.CopyTest@4b14c583 嵌套对象地址:com.wrx.king.entity.Trader@56a6d5a6
 浅拷贝:cglib.copy对象地址:com.wrx.king.entity.CopyTest@4ddced80 嵌套对象地址:com.wrx.king.entity.Trader@56a6d5a6
深拷贝:序列化反序列化对象地址:com.wrx.king.entity.CopyTest@79079097 嵌套对象地址:com.wrx.king.entity.Trader@4d1c00d0

总结jdk的clone方法和一般工具类的克隆方法都是浅拷贝,通过流序列化的原理就是深拷贝
深拷贝只能通过序列化和反序列化过程实现或者自己重写clone方法递归复制

标签:对象,clone,嵌套,地址,引用,拷贝,序列化
From: https://blog.csdn.net/wrxfxdd/article/details/140771347

相关文章

  • 为什么Python要对引用非容器类型的类型实现循环GC
    检查文档:支持循环垃圾收集Python对检测和收集涉及循环引用的垃圾的支持需要对象类型的支持,这些对象类型是其他对象的“容器”,这些对象也可能是容器不存储对其他对象的引用或仅存储对原子类型(例如数字或字符串)的引用的类型不需要为垃圾收集提供任何显......
  • Python学习手册(第四版)】学习笔记09.3-Python对象类型-分类、引用VS拷贝VS深拷贝、比较
    个人总结难免疏漏,请多包涵。更多内容请查看原文。本文以及学习笔记系列仅用于个人学习、研究交流。这部分稍杂,视需要选择目录读取。主要讲的是对之前的所有对象类型作复习,以通俗易懂、由浅入深的方式进行介绍,所有对象类型共有的特性(例如,共享引用),引用、拷贝、深拷贝,以及比较、......
  • 将 int[] arr1 ={10,20,30}; 拷贝到 arr2数组,要求数据空间是独立的。
    1publicclassshuzu06{2//编写一个main方法3publicstaticvoidmain(String[]args){45//将int[]arr1={10,20,30};拷贝到arr2数组,6//要求数据空间是独立的。78int[]arr1={10,20,30};910//创建一......
  • Java中的基本数据类型和引用数据类型
    目录前提介绍数据类型的作用数据类型的分类(1)基本数据类型(四类八种)(2)引用数据类型类(Class)接口(Interface)数组(Array)字符串(String)枚举(Enum)前提介绍java是一种强类型语言,这就意味着在编译的时候,所有的变量的数据类型都必须明确指定,并且类型系统会强制执行类型检查数据类型的作用在ja......
  • 15 赋值、浅拷贝和深拷贝区别_is和==的区别
     欢迎来到@一夜看尽长安花博客,您的点赞和收藏是我持续发文的动力对于文章中出现的任何错误请大家批评指出,一定及时修改。有任何想要讨论的问题可联系我:[email protected]。发布文章的风格因专栏而异,均自成体系,不足之处请大家指正。   专栏:java全栈C&C++PythonAIP......
  • C++第七次课笔记——引用
    引用作用:给变量取别名语法:数据类型&别名=原名intmain(){ //引用基本语法 inta=10; int&b=a; // cout<<"a="<<a<<endl; cout<<"b="<<b<<endl; b=100; cout<<"a="<<......
  • C++文件系统操作6 - 跨平台实现文件和文件夹的拷贝
    1.关键词2.fileutil.h3.fileutil.cpp4.filesystem_win.h5.filesystem_win.cpp6.filesystem_unix.cpp7.源码地址1.关键词C++文件系统操作拷贝文件拷贝文件夹跨平台2.fileutil.h#pragmaonce#include<string>#include<cstdio>#include<cstdint>#i......
  • C++深拷贝构造函数解决浅拷贝的堆区内存重复释放问题
    1.简单介绍先简单介绍一下浅拷贝和深拷贝:浅拷贝->简单的赋值拷贝操作,默认的拷贝构造函数就是浅拷贝。深拷贝->在堆区重新申请空间,进行拷贝操作。2.问题展示下面用代码示例明了地展示默认拷贝构造函数浅拷贝带来地堆区内存重复释放问题:#include<iostream>usingnamespace......
  • SQLAlchemy 无法通过多对多关系中的外键找到引用的表
    我已经成功在我的数据库中添加了一个多对多关系。但是,当尝试添加另一个时,我遇到了:sqlalchemy.exc.NoReferencedTableError:Foreignkeyassociatedwithcolumn'user_shiftTemplate.template_id'couldnotfindtable'shifttemplate'withwhichtogenerateaforeig......
  • 类库项目无法引用Microsoft.AspNetCore程序集下的类库
    类库项目无法引用Microsoft.AspNetCore程序集下的类库 在类库项目中不能直接引用WebApplicationBuilder、ApplicationBuilder等类,这些类位于Microsoft.ASPNetCore程序集中,但是无法通过Nuget包引用,因为该Nuget包的版本已经不再支持,很久没有更新过了。解决方法:在项目文件cspr......