目录
- 一、浅谈深拷贝和浅拷贝
- 二、浅拷贝和深拷贝的使用场景
-
- [1、浅拷贝在 Web 后端的应用](#1、浅拷贝在 Web 后端的应用)
-
- [1.DTO ↔ Entity 转换](#1.DTO ↔ Entity 转换)
- [2、深拷贝在 Web 后端的应用](#2、深拷贝在 Web 后端的应用)
-
- [1. 数据快照 / 历史归档](#1. 数据快照 / 历史归档)
- [2. 并发安全](#2. 并发安全)
一、浅谈深拷贝和浅拷贝
1、拷贝对象
对象拷贝(Object Copy)指将一个对象的属性复制到另一个类型相同的对象中。
在编程中,拷贝对象非常常见,通常是为了在新的环境中复用已有对象的数据。
1.浅拷贝 (Shallow Copy)
浅拷贝仅复制对象的引用,而不是对象本身。新旧对象共享同一块内存区域,修改其中一个对象会影响另一个。
-
拷贝基本类型
直接复制基本数据类型的值。
-
拷贝引用类型
仅复制引用地址,因此修改一个对象的数据会影响另一个对象。
-
总结
多个引用指向同一对象,修改其中一个会影响所有引用该对象的地方。
2.深拷贝 (Deep Copy)
深拷贝会创建一个新的对象,且新旧对象不共享内存,修改新对象不会影响原对象。
深拷贝复制源对象的所有属性,包括所有引用类型的对象,因此源对象和拷贝对象完全独立。
- 总结
深拷贝创建了一个完全独立的新对象,源对象和新对象之间没有任何引用关系。
2、为什么要使用深拷贝

避免共享引用
浅拷贝只是复制引用,可能导致修改副本时影响原对象。深拷贝确保创建独立副本,避免这种问题。
线程安全
在多线程环境中,多个线程可能同时修改同一个对象,造成数据冲突。使用深拷贝可以让每个线程操作独立副本,从而避免线程安全问题。
3、代码验证目录
1.cloneable接口
源码
知识点
- 如果类没有实现 Cloneable 接口,调用
clone()
方法时会抛出异常。 - 需要实现 Cloneable 接口后,才能正常调用
clone()
方法。
代码案例
2.浅拷贝示例
java
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
public class ShallowDeepCopyDemo
{
public static void main(String[] args) throws CloneNotSupportedException
{
m1();
}
private static void m1() throws CloneNotSupportedException
{
Emp emp = new Emp("z3", 15, "雷军", "CEO");
System.out.println("原始对象:" + emp.getBoss().getTitle());
Emp emp2 = (Emp) emp.clone();
System.out.println("拷贝对象:" + emp2.getBoss().getTitle());
System.out.println();
emp2.getBoss().setTitle("CTO");
System.out.println("------emp2拷贝对象修改Title=CTO,是否会影响原始对象");
System.out.println("原始对象:" + emp.getBoss().getTitle());
System.out.println("拷贝对象:" + emp2.getBoss().getTitle());
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
class Boss implements Cloneable
{
private String bossName;
private String title;
@Override
protected Object clone() throws CloneNotSupportedException
{
return super.clone();
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
class Emp implements Cloneable
{
private String empName;
private Integer age;
private Boss boss;
public Emp(String empName, Integer age, String bossName, String title)
{
this.empName = empName;
this.age = age;
this.boss = new Boss(bossName, title);
}
@Override
protected Object clone() throws CloneNotSupportedException
{
return super.clone();
}
}

3.深拷贝示例
修改Emp
当使用深拷贝,值就被修改了
二、浅拷贝和深拷贝的使用场景
1、浅拷贝在 Web 后端的应用
浅拷贝一般用在 对象之间的属性复制 或 轻量数据传输,因为它快、开销小。
1.DTO ↔ Entity 转换
在 Controller 层收到请求 DTO,需要转成 Entity 保存数据库时,常用浅拷贝工具类:
java
import org.springframework.beans.BeanUtils;
UserDTO dto = new UserDTO("Alice", 20);
UserEntity entity = new UserEntity();
BeanUtils.copyProperties(dto, entity); // 浅拷贝
System.out.println(entity.getName()); // Alice
👉 常见于:
- Request → Entity
- Entity → ResponseVO
1. 浅拷贝的本质
浅拷贝做的事情就是:
- 创建一个 新的外层对象 (
UserEntity
)。 - 把源对象(
UserDTO
)的字段值逐个赋值给目标对象的字段。 - 如果字段是基本类型 / 不可变对象 (
int
,long
,String
,Integer
...) → 拷贝的是值。 - 如果字段是可变引用对象 (
List
,Map
, 自定义对象) → 拷贝的是引用。
所以,BeanUtils.copyProperties(dto, entity)
只是"复制了一层属性",不会深度复制内部引用对象。
2. 为什么 DTO ↔ Entity 常用浅拷贝
我们来看常见代码:
java
UserDTO dto = new UserDTO("Alice", 20);
UserEntity entity = new UserEntity();
BeanUtils.copyProperties(dto, entity);
System.out.println(entity.getName()); // Alice
这里 name
是 String
,age
是 int
:
String
是不可变对象,即便两个对象指向同一个字符串引用也没问题。int
是基本类型,直接复制值,完全独立。
所以这种场景下,浅拷贝就够了。
3. 什么时候浅拷贝会出问题?
假设 DTO 里有个集合字段:
java
class UserDTO {
private String name;
private List<String> roles;
}
class UserEntity {
private String name;
private List<String> roles;
}
代码:
java
UserDTO dto = new UserDTO();
dto.setName("Alice");
dto.setRoles(new ArrayList<>(List.of("ADMIN")));
UserEntity entity = new UserEntity();
BeanUtils.copyProperties(dto, entity);
entity.getRoles().add("USER");
System.out.println(dto.getRoles()); // ❌ ["ADMIN", "USER"] 也被改了
👉 因为 roles
是可变对象,浅拷贝后 dto.roles
和 entity.roles
指向同一个 List
。
4. 为什么大部分场景没问题
- 在 Request → Entity 时,通常 DTO 里字段是简单类型(String, int),浅拷贝足够。
- 在 Entity → ResponseVO 时,也主要是简单类型(id, name, age, status),浅拷贝完全满足需求。
- 很少会直接把复杂的集合对象在 DTO 和 Entity 之间原样拷贝。即便有,也常常在 Service 层做 额外转换(比如 MapStruct、手写转换逻辑)。
5. 总结
BeanUtils.copyProperties
是 浅拷贝:只复制属性,不递归复制引用对象。- 在 DTO ↔ Entity 里,字段多为简单类型,所以浅拷贝完全够用。
- 如果有集合或嵌套对象,浅拷贝会共享引用,可能导致数据串改 → 这时要么手动处理,要么用 MapStruct 这种强类型映射工具。
2、深拷贝在 Web 后端的应用
深拷贝适合 数据快照 、并发安全 、防止数据污染 的场景。
1. 数据快照 / 历史归档
例如电商订单支付前,需要保存一份"冻结快照":
java
import com.fasterxml.jackson.databind.ObjectMapper;
ObjectMapper mapper = new ObjectMapper();
Order orderSnapshot = mapper.readValue(mapper.writeValueAsString(order), Order.class); // JSON 深拷贝
orderSnapshot.setStatus("FROZEN");
👉 这样修改快照不会影响到原始订单。
2. 并发安全
多线程处理时,如果多个线程共享对象,必须深拷贝避免互相污染:
java
Order original = orderService.getOrderById(1001);
Order threadOrder = (Order) SerializationUtils.clone(original); // Apache Commons 深拷贝
// 各线程独立处理自己的对象