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

深拷贝和浅拷贝

时间:2024-03-06 13:58:14浏览次数:14  
标签:obj 复杂 对象 实现 拷贝 序列化

前言

浅拷贝(shallow copy)和深拷贝(deep copy)是在编程中经常遇到的概念,尤其在处理数据结构时很重要。它们是针对对象(object)或数据结构(data structure)进行复制操作时的两种不同方式。

浅拷贝和深拷贝是在编程中常见的两种拷贝对象的方式,它们在拷贝对象时的行为和效果有所不同。

浅拷贝(Shallow Copy)

浅拷贝创建一个新对象,并将原始对象的字段值复制到新对象中。如果字段是值类型(如基本数据类型),则会复制其值。如果字段是引用类型,则会复制引用而不是引用的对象本身。

因此,浅拷贝会创建一个新对象,但是新对象中的引用类型字段仍然指向原始对象中相同的对象。

浅拷贝相对简单,但是可能导致对象之间的共享状态,如果对其中一个对象进行修改,则另一个对象也会受到影响。

深拷贝(Deep Copy)

深拷贝创建一个新对象,并递归地复制原始对象的所有字段,包括引用类型字段所引用的对象,以确保完全独立的拷贝。

深拷贝会遍历对象的所有字段,如果字段是引用类型,则会对其进行递归拷贝,以确保在新对象中创建相同的对象实例。

深拷贝会生成原始对象的完全独立副本,新对象和原始对象之间没有任何共享状态。

深拷贝实现方式

(一) 手动实现深拷贝

  • 手动遍历对象的所有字段,并为每个字段创建新的实例或进行递归拷贝。
  • 对于复杂对象结构,可能需要编写递归方法来处理深层嵌套的对象。
  • 这种方法需要手动编写拷贝逻辑,比较繁琐,但可以根据需要进行定制化的处理。

优点

  1. 精确控制:手动实现深拷贝可以让开发人员精确地控制拷贝过程,根据需要定制拷贝逻辑。这使得可以处理特定的场景和需求,例如特殊的对象结构或拷贝需求。
  2. 性能优化:由于手动实现深拷贝时可以针对具体情况进行优化,因此可能会比一般的通用方法更高效。例如,可以避免不必要的拷贝操作,减少性能开销。
  3. 灵活性:手动实现深拷贝可以根据具体需求选择不同的拷贝策略或实现方式,从而使得拷贝过程更加灵活和定制化。

缺点

  1. 繁琐复杂:手动实现深拷贝需要编写大量的代码来遍历对象的所有字段,并为每个字段创建新的实例或进行递归拷贝。这可能会导致代码量增加,维护成本较高。
  2. 容易出错:手动实现深拷贝可能会引入错误或遗漏,特别是对于复杂的对象结构或嵌套的对象关系。由于需要人工编写拷贝逻辑,因此容易出现疏漏或错误。
  3. 不适合大规模使用:手动实现深拷贝对开发人员的要求较高,特别是在处理复杂对象结构或大规模数据时。这可能会增加开发和测试的工作量,并且不适合频繁的使用。

(二) 表达式树

  • 表达式树是一种将代码表示为数据结构的方式,可以在运行时动态构建和修改代码。
  • 使用表达式树可以编写自定义的深拷贝方法,通过递归遍历对象的属性并创建新的实例,从而实现深拷贝。
  • 表达式树相对较为复杂,但提供了更高的灵活性,允许在运行时动态生成拷贝代码。
public class DeepCopyHelper
{
    public static T DeepCopy<T>(T obj)
    {
        ParameterExpression param = Expression.Parameter(typeof(T), "x");
        Expression<Func<T, T>> lambda = Expression.Lambda<Func<T, T>>(
            Expression.MemberInit(
                Expression.New(typeof(T)),
                typeof(T).GetProperties().Select(prop =>
                    Expression.Bind(prop, Expression.Property(param, prop))
                )
            ), param);

        return lambda.Compile()(obj);
    }
}

适用场景

  • 当需要高度控制拷贝过程,并且能够接受较高的实现复杂度时,表达式树是一个很好的选择。
  • 适用于需要在运行时动态生成拷贝代码的情况,以处理复杂的对象结构和特殊的拷贝需求。

优点

  • 提供了高度的灵活性,允许动态生成和修改拷贝代码。
  • 可以对拷贝过程进行细粒度的控制,处理特殊的拷贝需求。

缺点

  • 实现相对复杂,需要了解表达式树的工作原理和语法。
  • 由于动态生成代码,可能会引入性能开销。

(三) 反射

  • 反射是一种在运行时获取类型信息并调用其成员的机制,可以用于遍历对象的属性并复制它们。
  • 使用反射可以编写通用的深拷贝方法,通过获取对象的属性信息并创建新的实例来实现深拷贝。
  • 反射相对于表达式树来说稍微简单一些,但仍然需要处理类型的属性和字段。
public class DeepCopyHelper
{
    public static T DeepCopy<T>(T obj)
    {
        T newObj = (T)Activator.CreateInstance(obj.GetType());
        foreach (PropertyInfo property in obj.GetType().GetProperties())
        {
            if (property.CanWrite)
            {
                property.SetValue(newObj, property.GetValue(obj));
            }
        }
        return newObj;
    }
}

适用场景

  • 当对象的结构相对简单,并且希望使用通用的、简单的方法来实现深拷贝时,反射是一个不错的选择。
  • 适用于需要在运行时动态获取类型信息并处理属性的情况。

优点

  • 相对简单,容易理解和实现。
  • 适用于处理较简单的对象结构,无需复杂的拷贝逻辑。

缺点

  • 反射操作可能会引入一定的性能开销,特别是对于大型对象或高频率调用的情况。

(四) 序列化

  • 序列化是将对象转换为字节流或其他格式的过程,以便于存储、传输或复制。
  • 使用序列化可以实现深拷贝,通过将对象序列化为字节流,然后反序列化为新的对象实例。
  • 序列化是一种简单而强大的深拷贝方法,可以处理对象图中的循环引用和复杂结构,但可能会受到性能和序列化支持的限制。
   public static T DeepCopy<T>(T obj)
    {
        using (MemoryStream stream = new MemoryStream())
        {
            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(stream, obj);
            stream.Seek(0, SeekOrigin.Begin);
            return (T)formatter.Deserialize(stream);
        }
    }

适用场景

  • 当需要处理对象图中的循环引用、复杂结构或不可序列化的对象时,序列化是一个非常有用的方式。
  • 适用于需要简单快捷地实现深拷贝的情况。

优点

  • 简单快捷,适用于处理复杂的对象结构和循环引用。
  • 可以处理不可序列化的对象。

缺点

  • 可能会受到序列化和反序列化的性能开销。
  • 对于需要控制拷贝过程或处理特殊情况的需求,可能不够灵活。

(五) 对比

特征手动实现深拷贝表达式树反射序列化
实现复杂度 中等
灵活性 中等 中等
性能 取决于实现细节 中等 中等
定制化 可根据需求定制拷贝逻辑 有限,但可以灵活生成和修改代码 有限,主要用于获取和调用成员 有限,主要用于序列化和反序列化
容易出错 容易出错,特别是对于复杂对象结构 可能出错,特别是对于复杂的表达式 可能出错,特别是对于复杂的类型和结构 相对较少出错的可能性,但也可能有些问题
性能优化的空间 中等
适用场景 复杂对象结构、需要精确控制拷贝逻辑 需要动态生成和修改代码的情况 动态获取和调用对象成员的情况 处理复杂对象结构和循环引用时

标签:obj,复杂,对象,实现,拷贝,序列化
From: https://www.cnblogs.com/mchao/p/18056347

相关文章

  • 14_深拷贝
    深拷贝深拷贝是一种克隆类型,其中原始对象的所有字段和属性都会被复制到克隆中,包括嵌套对象。这意味着对克隆的任何更改都不会影响原始对象。ICloneable接口ICloneable接口允许.NET对象创建自身的一个副本,称为克隆。克隆与原始对象具有相同的值,但它们是独立的对象。实现IC......
  • 【个人前端笔记】手写对象深拷贝
    一、对象深拷贝简单的方法:JSON序列化方法通过将对象转换成JSON格式并转换回对象,实现深拷贝leta1={a:"hello",b:"world",c:[1,2,3],d:{a:1,b:2}}leta2=JSON.parse(JSON.stringify(a1))console.log(a2);JSON序列化拷贝的缺点a.不支持......
  • C++ 拷贝构造函数(初学有点难理解)
    拷贝构造函数是一种特殊的构造函数,它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象。拷贝构造函数通常用于:通过使用另一个同类型的对象来初始化新创建的对象。复制对象把它作为参数传递给函数。复制对象,并从函数返回这个对象。如果在类中没有定义拷......
  • 深浅拷贝
    当然,我可以帮你将这些Python代码转化为Markdown格式的笔记。以下是你的Markdown笔记:Python中的深浅拷贝在Python中,我们可以使用深浅拷贝来复制对象。深拷贝和浅拷贝的主要区别在于,对于复合对象(如列表、字典等),深拷贝会创建一个新的复合对象,并且递归地复制原对象中的所有元素,而浅......
  • 深拷贝与浅拷贝
    深拷贝与浅拷贝深拷贝对象的深拷贝是指其属性与其拷贝的源对象的属性不共享相同的引用点击查看MDN官网解释即深拷贝是值的拷贝,拷贝后的对象与源对象完全独立,互不影响浅拷贝对象的浅拷贝是其属性与其拷贝的源对象的属性共享引用--MDN点击查看MDN官网解释即深拷贝是值......
  • 多线程文件拷贝
    多线程文件拷贝#include<stdio.h>#include<pthread.h>#include<unistd.h>#include<stdlib.h>#include<assert.h>#include<sys/mman.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#inclu......
  • python 的深浅拷贝
    python的深浅拷贝在Python中,深拷贝(deepcopy)和浅拷贝(shallowcopy)是用于复制数据结构(如列表或字典)的两种不同方式,它们有以下区别:浅拷贝(ShallowCopy):浅拷贝创建一个新的对象,然后将原始对象中的元素(如果是可变对象)复制到新对象中。但是,如果元素本身也是一个可变对象,则新对象中的......
  • 多进程拷贝数据文件
    多进程拷贝数据#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<sys/mman.h>#include<sys/wait.h>#include<unistd.h>#include<stdio.h>#include<string.h>intmmap_mamcpy(char**argv){......
  • 零拷贝,mmap 和 sendFile
    传统的IOmmapmmap是一种内存映射技术,mmap相比于传统的IO来说,其实就是少了1次CPU拷贝而已,上图。sendFile在Linux中,提供sendFile函数,实现了零拷贝......
  • java实现scp功能实现目录下所有文件拷贝至指定服务器
    1、添加pom依赖<dependency><groupId>com.jcraft</groupId><artifactId>jsch</artifactId><version>0.1.55</version></dependency>2、示例代码publicstaticvoidmain(String[]args)throwsIOException{try{......