鸿蒙React Native提示聚合页开发:状态管理与性能优化实战
2026/10/17 11:05:48
深拷贝(Deep Copy)和浅拷贝(Shallow Copy)是编程中复制对象时的两种不同方式,核心区别在于是否递归复制对象内部的引用类型成员。
int、String、boolean)的值会被直接复制(值拷贝)。原对象 A ────┬──→ 基本字段:10(独立) └──→ 引用字段:Addr@123(指向堆中地址对象) 浅拷贝 B ───┬──→ 基本字段:10(独立副本) └──→ 引用字段:Addr@123(和 A 共享同一个地址对象!)address.city = "上海"):会影响原对象!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); // 输出 "上海" → 被影响了!原对象 A ───→ Addr@123(city="北京") 深拷贝 B ───→ Addr@456(city="北京")← 全新对象!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()) | 复杂(需递归或序列化) |
{...obj},Object.assign(),arr.slice()JSON.parse(JSON.stringify(obj))(有局限)structuredClone(obj)(现代浏览器)_.cloneDeep()(Lodash 库)copy.copy(obj)copy.deepcopy(obj)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, 自定义对象):这意味着:
如果你修改了目标对象中某个嵌套对象的属性,源对象也会被影响!
// 定义类 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的工作原理是:
它不会递归地为每个引用类型字段创建新实例,因此无法实现深拷贝 。
如果你需要深拷贝,可以考虑以下方案:
| 方法 | 说明 | 缺点 |
|---|---|---|
| 手动逐层复制 | 在 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是安全高效的;
一旦涉及可变的复杂对象图,请改用深拷贝方案 。