文章目录
- 前言
- 一、对象的深拷贝和浅拷贝
-
- [1.1 浅拷贝(Shadow Copy)](#1.1 浅拷贝(Shadow Copy))
- [1.2 深拷贝(Deep Copy)](#1.2 深拷贝(Deep Copy))
- [1.3 最直观对比图](#1.3 最直观对比图)
- [1.4 什么时候用?](#1.4 什么时候用?)
- 二、拷贝工具类:
-
- [2.1 浅拷贝](#2.1 浅拷贝)
- [2.2 深拷贝](#2.2 深拷贝)
- 总结
前言
本文记录一个java 对象的深度copy 工具类。
一、对象的深拷贝和浅拷贝
- 浅拷贝:只拷贝第一层,里面的引用对象还是同一个(改一个,另一个也变)
- 深拷贝:把整个对象树全部复制一份,两个对象完全独立(改一个,另一个不受影响)
1.1 浅拷贝(Shadow Copy)
原理:
- 基本类型:值拷贝
- 引用类型:只拷贝地址,共用同一个对象!
代码实现(实现 Cloneable 接口)
c
@Data
public class User implements Cloneable {
private String name;
private Address address; // 引用对象
// 浅拷贝
@Override
public User clone() {
try {
return (User) super.clone();
} catch (CloneNotSupportedException e) {
return null;
}
}
}
危险后果 :
c
User user1 = new User();
user1.setAddress(new Address("上海"));
User user2 = user1.clone(); // 浅拷贝
user2.getAddress().setCity("北京");
// 结果:user1 的城市也变成 北京!!!
1.2 深拷贝(Deep Copy)
原理
- 所有层级对象全部重新创建
- 拷贝后 两个对象 100% 独立,互不影响
最常用实现方式(序列化 / JSON)
c
// 深拷贝工具类
public static <T> T deepCopy(T obj, Class<T> clazz) {
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.readValue(mapper.writeValueAsString(obj), clazz);
} catch (Exception e) {
return null;
}
}
使用:
c
User user2 = deepCopy(user1, User.class);
user2.getAddress().setCity("北京");
// user1 完全不受影响 ✅
1.3 最直观对比图
浅拷贝
c
user1 ──┐
├─ name (复制)
└─ address → 【同一个对象】 ← user2.address
深拷贝
c
user1 ── name (复制)
└─ address → 对象A
user2 ── name (复制)
└─ address → 对象B(全新)
1.4 什么时候用?
- 基本类型、String → 浅拷贝就行
- 对象里有 自定义类、集合、数组 → 必须深拷贝
二、拷贝工具类:
2.1 浅拷贝
代码如下(示例): Spring 的 BeanUtils.copyProperties 是 浅拷贝(Shadow Copy)
c
import org.springframework.beans.BeanUtils;
BeanUtils.copyProperties(Object source, Object target)
2.2 深拷贝
代码如下(示例):
c
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Map;
/**
* copy
*/
public class DeepCopyUtil {
/**
* 深拷贝方法(支持父类字段)
*
* @param object 要拷贝的对象
* @param <T> 对象类型
* @return 深拷贝后的新对象
* @throws Exception 拷贝失败时抛出异常
*/
public static <T> T deepCopy(T object) throws Exception {
if (object == null) {
return null;
}
// 基本类型/不可变对象直接返回
if (isImmutable(object.getClass())) {
return object;
}
// 集合类特殊处理
if (object instanceof Collection) {
return (T) deepCopyCollection((Collection<?>) object);
}
if (object instanceof Map) {
return (T) deepCopyMap((Map<?, ?>) object);
}
// 数组处理
if (object.getClass().isArray()) {
return (T) deepCopyArray(object);
}
// 普通对象处理
return deepCopyObject(object);
}
// 判断是否为不可变类型
private static boolean isImmutable(Class<?> clazz) {
return clazz.isPrimitive()
||
Number.class.isAssignableFrom(clazz)
||
clazz == String.class
||
clazz == Boolean.class
||
clazz == Character.class;
}
// 深拷贝集合
private static <E> Collection<E> deepCopyCollection(Collection<E> collection) throws Exception {
Collection<E> copy = collection.getClass().newInstance();
for (E item : collection) {
copy.add(deepCopy(item));
}
return copy;
}
// 深拷贝Map
private static <K, V> Map<K, V> deepCopyMap(Map<K, V> map) throws Exception {
Map<K, V> copy = map.getClass().newInstance();
for (Map.Entry<K, V> entry : map.entrySet()) {
copy.put(deepCopy(entry.getKey()), deepCopy(entry.getValue()));
}
return copy;
}
// 深拷贝数组
private static Object deepCopyArray(Object array) throws Exception {
int length = Array.getLength(array);
Object newArray = Array.newInstance(array.getClass().getComponentType(), length);
for (int i = 0; i < length; i++) {
Array.set(newArray, i, deepCopy(Array.get(array, i)));
}
return newArray;
}
// 深拷贝普通对象(包含父类字段)
private static <T> T deepCopyObject(T object) throws Exception {
// 序列化方式实现深拷贝(简单但性能较低)
if (object instanceof Serializable) {
return serializableDeepCopy(object);
}
// 反射方式实现深拷贝(性能更好)
return reflectionDeepCopy(object);
}
// 通过序列化实现深拷贝
private static <T> T serializableDeepCopy(T object) throws Exception {
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos)) {
oos.writeObject(object);
try (ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais)) {
return (T) ois.readObject();
}
}
}
// 通过反射实现深拷贝(支持父类字段)
private static <T> T reflectionDeepCopy(T object) throws Exception {
@SuppressWarnings("unchecked")
Class<T> clazz = (Class<T>) object.getClass();
T copy = clazz.newInstance();
// 拷贝当前类及所有父类的字段
Class<?> currentClass = clazz;
while (currentClass != null && currentClass != Object.class) {
for (Field field : currentClass.getDeclaredFields()) {
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
continue; // 跳过静态字段
}
field.setAccessible(true);
Object value = field.get(object);
field.set(copy, deepCopy(value));
}
currentClass = currentClass.getSuperclass();
}
return copy;
}
}
总结
以上为 java 对象浅拷贝,深拷贝的介绍,使用场景,以及工具类的实现。