当前位置: 首页 > news >正文

深入探究编程拷贝

起因

        被一个问题问住了,JAVA里的“指针拷贝”,我的第一印象是JAVA是没有指针的?是不是引用拷贝。趁此机会,干脆总结一下各种拷贝把。

1. 浅拷贝(Shallow Copy)

  • 定义:只复制对象的最外层,如果对象包含嵌套对象(如数组、字典、引用类型等),则嵌套对象仍然是共享的(拷贝的是引用,而非实际数据)。

  • 特点

    • 基本类型(如数字、字符串)会完全复制。

    • 引用类型(如对象、数组)只会复制引用地址,新旧对象共享同一块内存。

  • 问题:修改拷贝后的对象中的嵌套属性时,原始对象也可能被修改。

  • 示例

    • JavaScript 的 Object.assign() 或扩展运算符 {...obj}

    • Python 的 copy.copy()

  • // JavaScript 示例
    const original = { a: 1, b: { c: 2 } };
    const shallowCopy = { ...original };
    shallowCopy.b.c = 99; // 修改嵌套属性
    console.log(original.b.c); // 输出 99(原始对象也被修改)

2. 深拷贝(Deep Copy)

  • 定义:完全复制对象及其所有嵌套对象,新旧对象完全独立,不共享任何内存。

  • 特点

    • 所有层级的数据都会被复制一份。

    • 修改拷贝后的对象不会影响原始对象。

  • 缺点:性能开销较大(尤其是嵌套层级深或数据量大时)。

  • 示例

    • JavaScript 的 JSON.parse(JSON.stringify(obj))(局限性:无法处理函数、undefined 等)。

    • Python 的 copy.deepcopy()

    • Lodash 的 _.cloneDeep()

    • // JavaScript 示例
      const original = { a: 1, b: { c: 2 } };
      const deepCopy = JSON.parse(JSON.stringify(original));
      deepCopy.b.c = 99;
      console.log(original.b.c); // 输出 2(原始对象不受影响)

 

3. 指针拷贝(引用拷贝)

  • 定义:直接复制对象的引用(内存地址),新旧变量指向同一块内存。

  • 特点

    • 没有创建新对象,只是多了一个指向原对象的指针。

    • 修改任意变量都会影响其他变量。

  • 示例

    • 大多数语言中直接赋值的行为(如 JavaScript 的对象赋值、Python 的列表赋值)。

// JavaScript 示例
const original = { a: 1 };
const pointerCopy = original; // 指针拷贝
pointerCopy.a = 2;
console.log(original.a); // 输出 2(原始对象被修改)

 

对比总结

拷贝方式复制内容嵌套对象是否独立性能典型场景
指针拷贝只复制引用(内存地址)❌ 共享最高需要引用同一对象时
浅拷贝复制外层,嵌套对象共享引用❌ 嵌套共享中等简单对象的快速复制
深拷贝递归复制所有层级✅ 完全独立最低需要完全独立的对象副本时

4. 写时拷贝(Copy-on-Write, COW)


8. 零拷贝(Zero-Copy)


9. 混合拷贝(Hybrid Copy)


注意事项

根据需求选择合适的拷贝方式:优先使用浅拷贝(性能高),必要时再用深拷贝(安全性高)。

  • 定义:一种优化技术,只有在数据被修改时才会真正执行拷贝,否则共享原始数据。

  • 特点

    • 初始时只是引用拷贝(类似指针拷贝),节省内存和计算资源。

    • 当尝试修改数据时,系统自动创建副本,确保原始数据不变。

  • 应用场景

    • 文件系统(如 Linux 的 fork() 子进程共享父进程内存,直到写入时才拷贝)。

    • 某些编程语言的数据结构(如 Swift 的 Array、Rust 的 Cow 类型)。

    • 数据库的快照隔离(Snapshot Isolation)。

  • // Rust 的 Cow(Copy-on-Write)示例
    use std::borrow::Cow;fn process_data(data: Cow<str>) {// 如果 data 是引用,且未被修改,则不会触发拷贝println!("Data: {}", data);
    }let static_str = "hello"; // 静态字符串(不可变)
    let owned_str = String::from("world"); // 可变字符串process_data(Cow::Borrowed(static_str)); // 不拷贝
    process_data(Cow::Owned(owned_str)); // 已拥有,无需拷贝

    5. 延迟拷贝(Lazy Copy)

  • 类似 COW,但更通用

    • 不一定是“写时”才拷贝,可能是按需计算或缓存结果后再拷贝。

    • 常见于函数式编程(如 Haskell 的惰性求值)。

  • 6. 结构化拷贝(Structured Clone)

  • 定义:一种比 JSON.parse(JSON.stringify()) 更强大的深拷贝方式,能处理循环引用、BlobDate 等特殊对象。

  • 特点

    • 浏览器环境支持 structuredClone() API。

    • Node.js 也有类似的实现(如 v8.deserialize(v8.serialize(obj)))。

  • 示例

  • const original = { a: 1, date: new Date(), nested: { b: 2 } };
    original.self = original; // 循环引用const cloned = structuredClone(original); // 正确处理循环引用和 Date
    console.log(cloned.date instanceof Date); // true

    7. 影子拷贝(Shadow Copy)

  • 定义:部分拷贝,仅复制对象的某些属性(如元数据),而非全部数据。

  • 应用场景

    • 数据库的“影子表”(Shadow Tables)。

    • 虚拟机的快照(仅记录变化部分)。

  • 定义:不复制数据,而是直接共享底层内存(如内存映射文件、DMA 传输)。

  • 特点

    • 最高性能,适合大数据传输(如网络协议、GPU 计算)。

    • 需要底层支持(如 Linux 的 sendfile()mmap())。

  • 定义:结合不同拷贝策略,如:

    • 浅拷贝 + 按需深拷贝(类似 COW)。

    • 部分深拷贝(如只复制某些嵌套层级)。

    • 示例

      • Node.js 的 stream.pipe()(零拷贝文件传输)。

      • Rust 的 Bytes 类型(引用计数共享内存)。

      对比总结

      拷贝方式是否共享数据触发条件典型应用场景
      指针拷贝✅ 共享直接赋值引用传递、性能优化
      浅拷贝❌(仅外层)显式调用简单对象复制
      深拷贝❌ 完全独立显式调用需要完全隔离的数据
      写时拷贝✅(初始)首次修改时高性能共享(如 fork()
      结构化拷贝❌ 完全独立显式调用浏览器环境深拷贝
      零拷贝✅ 共享底层优化大数据传输(如 mmap
      影子拷贝部分共享按需复制数据库快照、虚拟机

      如何选择合适的拷贝方式?

      • 默认用指针拷贝(如果不需要独立数据)。

      • 需要独立数据但性能敏感 → 浅拷贝或写时拷贝(COW)。

      • 需要完全隔离 → 深拷贝或结构化拷贝。

      • 大数据传输 → 零拷贝技术(如 mmapsendfile)。

      • 特殊需求(如循环引用)→ structuredClone 或自定义深拷贝。

    1. 循环引用:深拷贝时如果对象存在循环引用(如 a.b = a),普通方法会报栈溢出,需特殊处理。

    2. 特殊类型:函数、SymbolSet/Map 等可能需要额外处理。

    3. 语言差异:不同语言对浅拷贝/深拷贝的实现可能不同(如 Python 的 list.copy() 是浅拷贝)。

http://www.lryc.cn/news/585699.html

相关文章:

  • 基于Java Spring Boot开发的旅游景区智能管理系统 计算机毕业设计源码32487
  • 4万亿英伟达,凭什么?
  • 【Linux应用】Ubuntu20.04 aarch64开发板一键安装ROS2(清华源)
  • PandaCoder重大产品更新-引入Jenkinsfile文件支持
  • mysql的LIMIT 用法
  • 【AI大模型】超越RAG的搜索革命!分层框架让AI像专家团队一样深度思考
  • Java教程:JavaWeb ---MySQL高级
  • 隆重介绍 Xget for Chrome:您的终极下载加速器
  • linux kernel struct regmap_config结构详解
  • 【Quest开发】快速添加可手指触摸按钮
  • 3 OneNET-调试器模拟上报数据
  • Visual Studio Code 的 settings.json 配置指南
  • HarmonyOS NEXT端云一体化开发初体验
  • 世俱杯直播数据源通过反汇编获取到
  • gradle中namespace和applicationId的区别
  • Ubuntu20.04运行openmvg和openmvs实现三维重建(未成功,仅供参考)
  • 【酶解法】小鼠脾脏单细胞悬液的制备指南
  • 云网络产品
  • 7.11文件和异常
  • linux中cmake编译项目
  • 5G标准学习笔记15 --CSI-RS测量
  • Next知识框架、SSR、SSG和ISR知识框架梳理
  • SwiGLU是什么:Swish激活函数和门控线性单元(GLU)机制的激活函数
  • 2025 年第十五届 APMCM 亚太地区大学生数学建模竞赛C题 基于Quantum Boosting的二分类模型问题
  • 实时数仓和离线数仓还分不清楚?看完就懂了
  • defer关键字
  • PHT-CAD 笔记
  • 你见过的最差的程序员是怎样的?
  • docker设置代理
  • 秋招小白学数据结构-1-数据结构前置知识