news 2026/4/23 9:52:07

深拷贝和浅拷贝的区别,以及BeanUtils为什么是浅拷贝

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
深拷贝和浅拷贝的区别,以及BeanUtils为什么是浅拷贝

深拷贝(Deep Copy)和浅拷贝(Shallow Copy)是编程中复制对象时的两种不同方式,核心区别在于是否递归复制对象内部的引用类型成员


一、浅拷贝(Shallow Copy)

✅ 定义:
  • 创建一个新对象
  • 基本数据类型(如intStringboolean)的值会被直接复制(值拷贝)。
  • 引用类型(如对象、数组、List)只复制引用地址,不复制实际对象。
🧠 内存效果:
原对象 A ────┬──→ 基本字段:10(独立) └──→ 引用字段:Addr@123(指向堆中地址对象) 浅拷贝 B ───┬──→ 基本字段:10(独立副本) └──→ 引用字段:Addr@123(和 A 共享同一个地址对象!)
⚠️ 特点:
  • 修改基本类型字段:互不影响。
  • 修改引用类型字段的内容(如address.city = "上海"):会影响原对象!
💡 示例(Java):
class Address { String city; } class Person { String name; Address address; } // 浅拷贝(使用 clone() 默认行为) Person p1 = new Person(); p1.name = "张三"; p1.address = new Address(); p1.address.city = "北京"; Person p2 = (Person) p1.clone(); // 浅拷贝 p2.address.city = "上海"; // 修改引用对象 System.out.println(p1.address.city); // 输出 "上海" → 被影响了!

二、深拷贝(Deep Copy)

✅ 定义:
  • 创建一个全新的对象
  • 递归复制所有层级:不仅复制对象本身,还复制它引用的所有对象(子对象、孙子对象……)。
  • 新旧对象完全独立,没有任何共享引用。
🧠 内存效果:
原对象 A ───→ Addr@123(city="北京") 深拷贝 B ───→ Addr@456(city="北京")← 全新对象!
✅ 特点:
  • 修改任何字段(包括嵌套对象):都不会影响原对象
💡 示例(Java 手动实现):
class Address implements Cloneable { String city; public Address deepCopy() { Address a = new Address(); a.city = this.city; return a; } } class Person { String name; Address address; public Person deepCopy() { Person p = new Person(); p.name = this.name; p.address = this.address.deepCopy(); // 关键:也拷贝子对象 return p; } } Person p1 = new Person(); p1.address = new Address(); p1.address.city = "北京"; Person p2 = p1.deepCopy(); p2.address.city = "上海"; System.out.println(p1.address.city); // 输出 "北京" → 不受影响!

三、对比总结

特性浅拷贝深拷贝
基本类型字段复制值(独立)复制值(独立)
引用类型字段复制引用(共享对象)复制对象(全新实例)
内存占用
性能慢(需递归)
修改影响可能互相影响完全独立
实现难度简单(如clone()复杂(需递归或序列化)

四、常见语言中的实现方式

JavaScript
  • 浅拷贝:{...obj},Object.assign(),arr.slice()
  • 深拷贝:
    • JSON.parse(JSON.stringify(obj))(有局限)
    • structuredClone(obj)(现代浏览器)
    • _.cloneDeep()(Lodash 库)
Python
  • 浅拷贝:copy.copy(obj)
  • 深拷贝:copy.deepcopy(obj)
Java
  • 浅拷贝:Object.clone()(默认)
  • 深拷贝:
    • 重写clone()并递归克隆引用字段
    • 序列化/反序列化(要求实现Serializable

五、一句话记住

浅拷贝:只复制“外壳”,内部对象共享。
深拷贝:复制“整个家族”,完全独立。

当你需要完全隔离的数据副本(如导出、快照、撤销操作),用深拷贝;
如果只是临时读取或性能敏感,且不会修改嵌套对象,可用浅拷贝。

BeanUtils.copyProperties()不是深拷贝,而是典型的浅拷贝(Shallow Copy)


✅ 官方结论

无论是Spring Framework 的org.springframework.beans.BeanUtils.copyProperties
还是Apache Commons BeanUtils 的org.apache.commons.beanutils.BeanUtils.copyProperties
它们都只执行浅拷贝


🔍 什么是“浅拷贝”在此处的含义?

  • 对于基本数据类型(如int,String,Boolean):
    值会被复制到目标对象 → 修改互不影响 ✅
  • 对于引用类型(如Address,List, 自定义对象):
    只复制引用地址,不创建新对象 → 源对象和目标对象共享同一个子对象实例

这意味着:

如果你修改了目标对象中某个嵌套对象的属性,源对象也会被影响


🧪 示例说明(使用 Spring BeanUtils)

// 定义类 class Address { private String city; // getter/setter } class Person { private String name; private Address address; // getter/setter }
// 使用 copyProperties Person source = new Person(); source.setName("张三"); source.setAddress(new Address()); source.getAddress().setCity("北京"); Person target = new Person(); BeanUtils.copyProperties(source, target); // 浅拷贝! // 修改 target 的嵌套对象 target.getAddress().setCity("上海"); // 结果: System.out.println(source.getAddress().getCity()); // 输出 "上海"! System.out.println(target.getAddress().getCity()); // 输出 "上海"

💥 两个对象的address字段指向同一个Address实例,因此修改一个会影响另一个。


⚠️ 为什么不是深拷贝?

BeanUtils.copyProperties的工作原理是:

  1. 通过反射获取源对象的getter 方法
  2. 调用目标对象的setter 方法
  3. 直接赋值返回的对象引用

不会递归地为每个引用类型字段创建新实例,因此无法实现深拷贝 。


✅ 如何实现真正的深拷贝?

如果你需要深拷贝,可以考虑以下方案:

方法说明缺点
手动逐层复制在 setter 中 new 子对象并复制属性代码冗长,维护成本高
序列化/反序列化使用ObjectOutputStream或 FastJSON/Jackson要求所有类实现Serializable,性能较差
第三方库如 Dozer、ModelMapper、MapStruct需引入依赖,学习成本
JSON 中转(慎用)JSON.parseObject(JSON.toJSONString(obj), Clazz)可能丢失类型信息(如 Date 变时间戳),且有性能开销

示例(Jackson 深拷贝):

ObjectMapper mapper = new ObjectMapper(); String json = mapper.writeValueAsString(source); Target target = mapper.readValue(json, Target.class); // 真正的深拷贝

📌 总结

问题回答
BeanUtils.copyProperties是深拷贝吗?不是,是浅拷贝
能否用于含嵌套对象的 DTO 转换?⚠️可以,但要确保后续不修改嵌套对象,否则会污染源数据
修改目标对象会影响源对象吗?如果修改的是引用类型的内部状态,会!
推荐在什么场景使用?✅ 仅包含基本类型或不可变对象(如String)的 POJO 复制

💡最佳实践
当你的 DTO/Entity没有嵌套对象,或嵌套对象不会被修改时,BeanUtils.copyProperties是安全高效的;
一旦涉及可变的复杂对象图,请改用深拷贝方案 。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/29 20:47:29

兰亭妙微:以交互设计×界面设计×VUE开发,重塑智慧商保理赔新体验

在数字化浪潮席卷医疗与保险行业的今天,“高效、安全、暖心”成为智慧商保产品的核心竞争力。保信健康宝——这款联合保险公司、医院打造的统一线上理赔服务平台,凭借区块链技术与银行级加密传输的双重保障,以及极速到账的理赔优势&#xff0…

作者头像 李华
网站建设 2026/4/18 11:31:23

我国四大领海之一的黄海,南北到底有多长?

黄海是太平洋西部的边缘海,是西太平洋典型的一个半封闭边缘海,它位于中国与朝鲜半岛之间。 它是一个近似南北向的半封闭海。 行政区跨辽宁省、山东省、江苏省,地理位置为北纬3140.0′~3954.1′,东经11910.9′~12650.0′。 黄海…

作者头像 李华
网站建设 2026/4/13 6:34:13

基于Java+SpringBoot+SSM家庭医生服务软件(源码+LW+调试文档+讲解等)/家庭医生APP/家庭医生系统/医疗服务软件/在线家庭医生/医生服务应用/家庭健康软件/医疗服务平台

博主介绍 💗博主介绍:✌全栈领域优质创作者,专注于Java、小程序、Python技术领域和计算机毕业项目实战✌💗 👇🏻 精彩专栏 推荐订阅👇🏻 2025-2026年最新1000个热门Java毕业设计选题…

作者头像 李华
网站建设 2026/4/21 17:00:08

基于Java+SpringBoot+SSM师生互动桥系统(源码+LW+调试文档+讲解等)/师生互动平台系统/师生互动教学系统/互动桥梁系统/师生交流桥系统/教学互动桥系统

博主介绍 💗博主介绍:✌全栈领域优质创作者,专注于Java、小程序、Python技术领域和计算机毕业项目实战✌💗 👇🏻 精彩专栏 推荐订阅👇🏻 2025-2026年最新1000个热门Java毕业设计选题…

作者头像 李华
网站建设 2026/4/16 20:46:30

【CDA干货】6个超好用的网站,全流程解决数据分析难题

一、找数据:镝数聚聚合了全球8000多家权威数据源,内容涵盖了社会、互联网与通信、经济与商业、生活娱乐、消费市场、金融、媒介与广告、健康与制药、工业、能源与环境、运输与物流、农业等16大领域、120多个垂直行业。镝数图表拥有上百种图表模板&#x…

作者头像 李华
网站建设 2026/4/15 8:54:27

香橙派通过VNC连接后处于管理员界面的切换为普通用户界面

首先当我们通过realVNC中连接上香橙派后,在终端里输入 whoami 后提示出来的是: 如果输出是 root:说明你的 VNC 服务是用管理员权限开启的。 如果输出是 HwHiAiUser:说明用户没问题,只是 Shell 没加载对…

作者头像 李华