游乐游手机版
首页/前端开发/文章详情

原型式继承实现深拷贝对象的方法详解

时间:2026-06-28 06:35
原型式继承本质上是浅拷贝,仅实现属性委托复用而无法深拷贝。深拷贝需手动重写clone方法递归复制引用字段,或采用序列化(需实现Serializable)及第三方工具(如ApacheCommonsLang、Jackson)来生成完全独立的对象副本,彼此改动互不影响。

原型式继承默认只提供浅拷贝机制,许多开发者容易将其与深拷贝混淆。它本质上是通过对象的 prototype 或者 Object.create() 实现属性和方法的委托复用——简单来说,子对象可以沿着原型链访问父对象定义的成员。而深拷贝解决的是完全不同的需求:为每个新对象创建一份完全独立的数据副本,确保互不干扰。

原型式继承怎么实现深拷贝对象的克隆?

举例来说,原型继承下多个实例共享同一个引用类型字段,修改一个实例会影响所有其他实例;而深拷贝要求每个实例拥有独立的数据副本,改动互不影响。两者的目标截然不同,实际开发中常常需要将它们结合使用,既能复用行为逻辑,又能隔离每个实例的状态。

那么,如何将深拷贝的逻辑融入原型继承的框架呢?常见的方法主要有以下三种。

手动重写 clone 方法

最直接的方式是在每个具体的原型类中重写 clone() 方法,对每个引用类型字段进行递归处理。基本类型字段直接赋值,数组使用 Arrays.copyOf() 或流式复制完成。对于嵌套对象,必须确保该对象本身支持克隆——即其类必须实现 Cloneable 接口并重写 clone() 方法。特别注意,不要直接调用 super.clone(),因为它仅执行浅拷贝,引用字段复制后依然指向同一对象地址。

打个比方,这就好比复制一份公司架构图:浅拷贝只是复印纸面,纸上的箭头仍指向原部门;深拷贝则重新创建每个部门和团队,箭头指向全新的副本。

用序列化实现通用深拷贝

如果对象层级特别深,手动逐层编写 clone 方法会非常繁琐。这时可以考虑序列化方案——前提是对象及其所有成员都必须实现 Serializable 接口。思路很简单:创建 ByteArrayOutputStreamObjectOutputStream,将原对象写入字节流,再通过 ObjectInputStream 从流中读出新对象。该过程自动处理任意深度的引用链,完全无需手动遍历。

不过这个方案也有硬伤:如果对象包含不可序列化的字段,比如 ThreadSocket,则这条路就走不通了。必须警惕的是,这不是“可能失败”,而是“必定失败”——所以使用前务必将对象的序列化能力摸清楚。

借助第三方工具简化操作

如果希望避免与 CloneableSerializable 等接口打交道,Apache Commons Lang 和 Jackson 提供了更便捷的途径。例如 SerializationUtils.clone(obj) 将上述序列化流程封装为一行调用,使用起来极其简单。或者利用 Jackson 的树模型,先将对象转为 JsonNode,再反序列化为新实例——这种方式适用于 POJO 场景,且不要求对象实现 Cloneable

当然,这类方案也并非万能。它们要求对象的字段能够被 JSON 序列化,如果字段类型比较复杂,或者存在自定义序列化逻辑,仍需提前验证兼容性。

从实际应用角度看,三种方法各有利弊。手动重写最灵活但也最繁琐,序列化方案最简洁但有接口约束,第三方工具最省事但依赖外部库。具体选择哪一种,最终取决于项目约束和团队习惯。

来源:https://www.php.cn/faq/2677593.html
上一篇Vue全局状态数据一键清空的完整实现方法 下一篇Promise.then异步特性在事件循环中的体现
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
如何在JavaScript中实现基于旋转视野的FOV射线绘制详解
前端开发 · 2026-07-01

如何在JavaScript中实现基于旋转视野的FOV射线绘制详解

如果用一句话概括核心,那就是:在 RayCasting 游戏开发中,绘制动态视野边界线(FOV)最可靠的方式是在逻辑层通过数学公式将坐标“算”出来,而不是依赖 Canvas 绘图上下文的旋转操作。 在实现类似 Doom 风格的 RayCasting 游戏时,动态视野(Field of View, F

TypeScript后端数据正确映射为前端接口类型的方法
前端开发 · 2026-07-01

TypeScript后端数据正确映射为前端接口类型的方法

在后端数据与前端类型之间来回转换,几乎是每位 TypeScript 开发者都无法回避的常态。后端返回的 car_brand、reg_number,和前端接口中定义的 brand、govtNumber,命名风格常常对不上号。此时,如果为了省事直接用 as 类型断言“强行”指认类型,那就踩进了常见的陷阱

动态HTML表格按层级条件合并单元格的JavaScript实现
前端开发 · 2026-07-01

动态HTML表格按层级条件合并单元格的JavaScript实现

本文详细讲解一种递归式 JavaScript 合并单元格方法,用于按列优先级(如前3列)智能合并表格行:仅当前一列已合并的前提下,才允许后续列合并相同值,从而精准实现多级分组与层级表格合并效果。 在动态生成的 HTML 表格中,按业务逻辑合并重复行是常见需求。然而,简单地对单列分别遍历合并——例如先

Next.js 13+重定向后滚动失效解决方案
前端开发 · 2026-07-01

Next.js 13+重定向后滚动失效解决方案

在 Next js App Router 的日常开发中,有一个令人颇为困扰的异常现象——当服务端执行 `redirect()` 跳转后,目标页面竟然无法正常滚动。没错,页面已经渲染完成,内容也完整显示,但垂直滚动条仿佛凭空消失。这个问题在 Next js 13 5 4 版本中尤为突出。 先给出结论:

WebGL图像加载延迟的纹理初始化时立即显示方法
前端开发 · 2026-07-01

WebGL图像加载延迟的纹理初始化时立即显示方法

本文详细介绍如何利用 Promise 与 async await 重构 WebGL 纹理加载流程,彻底解决首次渲染显示蓝色占位色、需要手动交互才能刷新的问题,实现文件导入后四张纹理平面即时正确渲染。 实际上,这个坑在 WebGL 开发中相当常见——纹理异步加载的小陷阱,说起来不大,但第一次遇到确实令