Java面试之深拷贝与浅拷贝的区别

发布时间 - 2026-01-10 00:00:00    点击率:
浅拷贝只复制对象本身而不复制引用指向的堆内存,导致新旧对象共享引用对象;深拷贝需递归复制所有层级引用,确保完全独立。

浅拷贝只复制对象本身,不复制引用指向的堆内存

当你调用 Object.clone() 且该类没重写 clone() 或没实现 Cloneable,会抛出 CloneNotSupportedException。即使成功,默认行为是浅拷贝:基本类型字段值被复制,引用类型字段只复制地址,新旧对象共享同一堆内存中的对象。

常见错误现象:修改克隆后对象的某个 List 元素,原对象也跟着变;toString() 输出看似不同,但 == 比较引用字段返回 true

  • 必须显式实现 Cloneable 接口(仅作标记,无方法)
  • protectedclone() 需改为 public 并处理异常
  • 对每个可变引用字段(如 ArrayList、自定义对象),要手动调用其 clone() 或新建实例并复制内容

深拷贝要递归复制所有层级的引用对象

深拷贝的目标是让克隆对象与原对象完全独立,任意一方修改内部状态都不影响另一方。没有语言级内置支持,必须手动实现或借助工具。

使用场景包括:缓存中返回对象副本避免污染、多线程间安全传递可变对象、测试中隔离 fixture 状态。

  • 手动实现:重写 clone(),对每个引用字段 new 一个新对象,并递归调用其 clone()(要求它们也支持)
  • 序列化方式(如 ObjectOutputStream + ByteArrayInputStream):要求所有字段类型都实现 Serializable,且注意 transient 字段丢失、性能差、无法处理循环引用
  • JSON 序列化(如 Jackson):简单但有类型擦除风险(泛型信息丢失)、不支持非 public 字段、忽略 transient 和静态字段

为什么 Arrays.copyOf()new ArrayList(list) 不是深拷贝

这些操作常被误认为“深拷贝”,其实只是对容器本身做了浅层复制 —— 新建了数组或 ArrayList 实例,但其中元素仍是原引用。

String[] arr1 = {"a", "b"};
String[] arr2 = Arrays.copyOf(arr1, arr1.length);
arr2[0] = "x"; // ✅ arr1[0] 还是 "a",String 不可变,看不出来
List list1 = Arrays.asList(new StringBuilder("hello"));
List list2 = new ArrayList<>(list1);
list2.get(0).append("!"); // ❌ list1.get(0) 也会变成 "hello!"
  • Arrays.copyOf() 复制的是数组引用本身,不是元素内容
  • new ArrayList(collection) 调用的是 addAll(),本质是遍历赋值引用
  • 只有元素是不可变对象(如 StringInteger)时,浅拷贝“看起来”像深拷贝

面试中容易被追问的边界点

面试官常从实现细节切入,比如:如果对象里有 final 字段、有 ThreadLocal、含 Lambda 表达式、或继承自第三方类无法修改源码,怎么办?

  • final 引用字段在浅拷贝中无法重新赋值,必须在构造时初始化,深拷贝需通过反射绕过(不推荐)或改用工厂方法
  • ThreadLocal 是线程绑定的,不应被拷贝;若强行序列化会失效,应明确设计为“不参与拷贝”
  • Lambda 表达式编译后是私有静态方法+捕获变量,序列化可能失败;建议避免在需深拷贝的对象中持有 Lambda
  • 无法修改父类时,子类 clone() 中对父类引用字段的深拷贝逻辑必须小心:不能访问 super.clone() 返回对象的私有字段

真正难的不是写出一个能跑的 clone 方法,而是判断哪些字段必须深拷、哪些可以共享、哪些根本不该拷贝 —— 这取决于业务语义,不是技术规则能覆盖的。


# java  # js  # json  # app  # 工具  # stream  # 区别  # 为什么 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: Laravel如何发送邮件_Laravel Mailables构建与发送邮件的简明教程  Mybatis 中的insertOrUpdate操作  Java类加载基本过程详细介绍  网站制作怎么样才能赚钱,用自己的电脑做服务器架设网站有什么利弊,能赚钱吗?  Windows11怎样设置电源计划_Windows11电源计划调整攻略【指南】  用v-html解决Vue.js渲染中html标签不被解析的问题  北京企业网站设计制作公司,北京铁路集团官方网站?  laravel服务容器和依赖注入怎么理解_laravel服务容器与依赖注入解析  Laravel Blade组件怎么用_Laravel可复用视图组件的创建与使用  Python自然语言搜索引擎项目教程_倒排索引查询优化案例  如何在香港免费服务器上快速搭建网站?  如何基于云服务器快速搭建网站及云盘系统?  矢量图网站制作软件,用千图网的一张矢量图做公司app首页,该网站并未说明版权等问题,这样做算不算侵权?应该如何解决?  如何确保FTP站点访问权限与数据传输安全?  jquery插件bootstrapValidator表单验证详解  网站制作大概多少钱一个,做一个平台网站大概多少钱?  Laravel中DTO是什么概念_在Laravel项目中使用数据传输对象(DTO)  Python制作简易注册登录系统  Bootstrap整体框架之CSS12栅格系统  哪家制作企业网站好,开办像阿里巴巴那样的网络公司和网站要怎么做?  百度输入法ai组件怎么删除 百度输入法ai组件移除工具  Laravel Admin后台管理框架推荐_Laravel快速开发后台工具  Laravel Artisan命令怎么自定义_创建自己的Laravel命令行工具完全指南  如何用IIS7快速搭建并优化网站站点?  Win11摄像头无法使用怎么办_Win11相机隐私权限开启教程【详解】  lovemo网页版地址 lovemo官网手机登录  Laravel怎么定时执行任务_Laravel任务调度器Schedule配置与Cron设置【教程】  浅谈Javascript中的Label语句  Thinkphp 中 distinct 的用法解析  公司网站制作价格怎么算,公司办个官网需要多少钱?  C语言设计一个闪闪的圣诞树  如何快速搭建高效简练网站?  Laravel中Service Container是做什么的_Laravel服务容器与依赖注入核心概念解析  Python文件异常处理策略_健壮性说明【指导】  网站设计制作书签怎么做,怎样将网页添加到书签/主页书签/桌面?  标题:Vue + Vuex + JWT 身份认证的正确实践与常见误区解析  Laravel怎么使用Collection集合方法_Laravel数组操作高级函数pluck与map【手册】  如何挑选最适合建站的高性能VPS主机?  Laravel与Inertia.js怎么结合_使用Laravel和Inertia构建现代单页应用  logo在线制作免费网站在线制作好吗,DW网页制作时,如何在网页标题前加上logo?  JavaScript中如何操作剪贴板_ClipboardAPI怎么用  如何彻底删除建站之星生成的Banner?  php在windows下怎么调试_phpwindows环境调试操作说明【操作】  Android okhttputils现在进度显示实例代码  高配服务器限时抢购:企业级配置与回收服务一站式优惠方案  laravel怎么配置Redis作为缓存驱动_laravel Redis缓存配置教程  实例解析angularjs的filter过滤器  如何获取上海专业网站定制建站电话?  如何快速上传建站程序避免常见错误?  简单实现Android文件上传