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

深入探究编程拷贝

起因

        被一个问题问住了,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.xdnf.cn/news/15085.html

相关文章:

  • 【Spring Boot】Spring Boot 4.0 的颠覆性AI特性全景解析,结合智能编码实战案例、底层架构革新及Prompt工程手册
  • Vue 表单开发优化实践:如何优雅地合并 `data()` 与 `resetForm()` 中的重复对象
  • 两台电脑通过网线直连形成局域网,共享一台wifi网络实现上网
  • 排序算法(一):冒泡排序
  • nginx 负载均衡配置(加解决重复登录问题)
  • 没有管理员权限,在服务器安装使用 Jupyter + R 内核
  • 【Linux仓库】命令行参数与环境变量【进程·伍】
  • 如何通过多点监控提升公网 IP 的稳定性和访问可用性
  • 全球化 2.0 | 印尼金融科技公司通过云轴科技ZStack实现VMware替代
  • 业务建模如何让金融数字化转型 “轻” 装上
  • rom定制系列------红米note10 5G版camellia原生安卓14批量线刷 miui安卓11修改型号root版
  • C语言:20250711笔记
  • 动态规划初步(完全背包)
  • T16IZ遥控器教程__遥控器与无人机对频
  • 线性回归原理推导与应用(十):逻辑回归多分类实战
  • 视频人脸处理——人脸面部动作提取
  • Spring Boot主从数据库完全教程 - 从零到精通
  • ubuntu22默认安装firefox使用snap安装还老打不开解决办法
  • Unity Demo——3D平台跳跃游戏笔记
  • IDE 关联 Git 操作
  • Flutter、Vue 3 和 React 在 UI 布局比较
  • windows下安装 redis
  • 代账行业数字化破局:从“知道”到“做到”,三步走稳赢!
  • 【Java】【力扣】102.二叉树层序遍历
  • 【TCP/IP】18. 因特网服务质量
  • PyTorch 与 Spring AI 集成实战
  • 【操作系统】线程
  • vue3 el-input 通过数组 获取显示
  • docker 启动中间件
  • LeetCode 148 排序链表解析:高效归并排序实现