深拷贝是我们在代码开发当中经常需要使用到的,但是市面上的对象拷贝方法,比如spring自带的,或者其他工具类带的对象拷贝,大部分都是浅拷贝,根本无法满足咱们的业务需求,我们就只能对里面的引用对象进行专门的赋值动作,比较麻烦。
今天我会为大家分享我在工作当中经常使用到的深拷贝工具类,并会为大家一一分析讲解,当前类已经在生产中实践过,没有什么问题,大家可以基于自己的实际情况进行使用。希望大家多多关注点赞支持,后续继续为大家分享有用的知识点!!
1. 深拷贝和浅拷贝的概念
深拷贝和浅拷贝是指在赋值一个对象时,拷贝的深度不同。
在进行深拷贝时,会拷贝所有的属性,并且如果这些属性是对象,也会对这些对象进行深拷贝,直到最底层的基本数据类型为止。这意味着,对于深拷贝后的对象,即使原对象的属性值发生了变化,深拷贝后的对象的属性值也不会受到影响。
2. 深拷贝和浅拷贝的区别
- 浅拷贝仅仅复制对象的引用,而不是对象本身,新旧对象共享同一块内存。
- 深拷贝会拷贝所有的属性,并且如果这些属性是对象,也会对这些对象进行深拷贝,直到最底层的基本数据类型为止。新对象和原对象没有任何关联,修改新对象不影响原对象。
3. 赋值和拷贝的区别
区别1:赋值是指赋值者与被赋值者指向的是同一地址,只是标签不同,当a的内容被修改之后,b也发生改变;而拷贝是指把原来的值复制了一份存在另一个地址,当原地址的内容被改变之后,拷贝的内容不变。
区别2:赋值侧重于更新,构造侧重于构造。 等号不等于赋值,他可能是拷贝构造。
4. 工具类
要注意,我在底层引用了hutool和lombok,所以在使用之前一定要引入这两个依赖。
我在工具类里面提供了如下功能:
- 单对象基于class创建拷贝
- 单对象基于对象创建拷贝
- 列表对象基于class创建拷贝
- 对象转Map
- map基于class拷贝到bean
- map基于对象拷贝到bean
- map拷贝到map
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class BeanCopyUtils {
/**
* 单对象基于class创建拷贝
*
* @param source 数据来源实体
* @param desc 描述对象 转换后的对象
* @return desc
*/
public static <T, V> V copy(T source, Class<V> desc) {
if (ObjectUtil.isNull(source)) {
return null;
}
if (ObjectUtil.isNull(desc)) {
return null;
}
final V target = ReflectUtil.newInstanceIfPossible(desc);
return copy(source, target);
}
/**
* 单对象基于对象创建拷贝
*
* @param source 数据来源实体
* @param desc 转换后的对象
* @return desc
*/
public static <T, V> V copy(T source, V desc) {
if (ObjectUtil.isNull(source)) {
return null;
}
if (ObjectUtil.isNull(desc)) {
return null;
}
BeanCopier beanCopier = BeanCopierCache.INSTANCE.get(source.getClass(), desc.getClass(), null);
beanCopier.copy(source, desc, null);
return desc;
}
/**
* 列表对象基于class创建拷贝
*
* @param sourceList 数据来源实体列表
* @param desc 描述对象 转换后的对象
* @return desc
*/
public static <T, V> List<V> copyList(List<T> sourceList, Class<V> desc) {
if (ObjectUtil.isNull(sourceList)) {
return null;
}
if (CollUtil.isEmpty(sourceList)) {
return CollUtil.newArrayList();
}
return StreamUtils.toList(sourceList, source -> {
V target = ReflectUtil.newInstanceIfPossible(desc);
copy(source, target);
return target;
});
}
/**
* bean拷贝到map
*
* @param bean 数据来源实体
* @return map对象
*/
public static <T> Map<String, Object> copyToMap(T bean) {
if (ObjectUtil.isNull(bean)) {
return null;
}
return BeanMap.create(bean);
}
/**
* map拷贝到bean
*
* @param map 数据来源
* @param beanClass bean类
* @return bean对象
*/
public static <T> T mapToBean(Map<String, Object> map, Class<T> beanClass) {
if (MapUtil.isEmpty(map)) {
return null;
}
if (ObjectUtil.isNull(beanClass)) {
return null;
}
T bean = ReflectUtil.newInstanceIfPossible(beanClass);
return mapToBean(map, bean);
}
/**
* map拷贝到bean
*
* @param map 数据来源
* @param bean bean对象
* @return bean对象
*/
public static <T> T mapToBean(Map<String, Object> map, T bean) {
if (MapUtil.isEmpty(map)) {
return null;
}
if (ObjectUtil.isNull(bean)) {
return null;
}
BeanMap.create(bean).putAll(map);
return bean;
}
/**
* map拷贝到map
*
* @param map 数据来源
* @param clazz 返回的对象类型
* @return map对象
*/
public static <T, V> Map<String, V> mapToMap(Map<String, T> map, Class<V> clazz) {
if (MapUtil.isEmpty(map)) {
return null;
}
if (ObjectUtil.isNull(clazz)) {
return null;
}
Map<String, V> copyMap = new LinkedHashMap<>(map.size());
map.forEach((k, v) -> copyMap.put(k, copy(v, clazz)));
return copyMap;
}
/**
* BeanCopier属性缓存<br>
* 缓存用于防止多次反射造成的性能问题
*/
public enum BeanCopierCache {
/**
* BeanCopier属性缓存单例
*/
INSTANCE;
private final SimpleCache<String, BeanCopier> cache = new SimpleCache<>();
/**
* 获得类与转换器生成的key在{@link BeanCopier}的Map中对应的元素
*
* @param srcClass 源Bean的类
* @param targetClass 目标Bean的类
* @param converter 转换器
* @return Map中对应的BeanCopier
*/
public BeanCopier get(Class<?> srcClass, Class<?> targetClass, Converter converter) {
final String key = genKey(srcClass, targetClass, converter);
return cache.get(key, () -> BeanCopier.create(srcClass, targetClass, converter != null));
}
/**
* 获得类与转换器生成的key
*
* @param srcClass 源Bean的类
* @param targetClass 目标Bean的类
* @param converter 转换器
* @return 属性名和Map映射的key
*/
private String genKey(Class<?> srcClass, Class<?> targetClass, Converter converter) {
final StringBuilder key = StrUtil.builder()
.append(srcClass.getName()).append('#').append(targetClass.getName());
if (null != converter) {
key.append('#').append(converter.getClass().getName());
}
return key.toString();
}
}
}
5. 举例
5.1 对象之间相互拷贝
public static void main(String[] args) {
SysUser sysUser1 = new SysUser();
SysDept sysDept = new SysDept();
sysDept.setDeptId(111L);
List<SysRole> roles = new ArrayList<>(){{add(new SysRole(1234L));}};
sysUser1.setUserId(100L);
sysUser1.setDept(sysDept);
sysUser1.setRoles(roles);
SysUser sysUser2 = new SysUser();
BeanCopyUtils.copy(sysUser1,sysUser2);
System.out.println(sysUser2);
}
运行结果:
SysUser(userId=100, deptId=null, userName=null, nickName=null, userType=null, email=null, phonenumber=null, sex=null, avatar=null, password=null, status=null, delFlag=null, loginIp=null, loginDate=null, remark=null, dept=SysDept(deptId=111, deptName=null, orderNum=null, leader=null, phone=null, email=null, status=null, delFlag=null, ancestors=null), roles=[SysRole(roleId=1234, roleName=null, roleKey=null, roleSort=null, dataScope=null, menuCheckStrictly=null, deptCheckStrictly=null, status=null, delFlag=null, remark=null, flag=false, menuIds=null, deptIds=null)], roleIds=null, postIds=null, roleId=null)
可以清楚地看到角色集合ID,部门对象ID,用户ID都被拷贝进去了。
5.2 对象拷贝到Map
public static void main(String[] args) {
SysUser sysUser1 = new SysUser();
SysDept sysDept = new SysDept();
sysDept.setDeptId(111L);
List<SysRole> roles = new ArrayList<>(){{add(new SysRole(1234L));}};
sysUser1.setUserId(100L);
sysUser1.setDept(sysDept);
sysUser1.setRoles(roles);
Map<String, Object> stringObjectMap = BeanCopyUtils.copyToMap(sysUser1);
System.out.println(stringObjectMap);
}
运行结果
{roles=[SysRole(roleId=1234, roleName=null, roleKey=null, roleSort=null, dataScope=null, menuCheckStrictly=null, deptCheckStrictly=null, status=null, delFlag=null, remark=null, flag=false, menuIds=null, deptIds=null)], phonenumber=null, admin=false, loginDate=null, remark=null, delFlag=null, password=null, updateBy=null, postIds=null, loginIp=null, email=null, nickName=null, roleId=null, sex=null, deptId=null, updateTime=null, avatar=null, dept=SysDept(deptId=111, deptName=null, orderNum=null, leader=null, phone=null, email=null, status=null, delFlag=null, ancestors=null), params={}, userName=null, userId=100, createBy=null, roleIds=null, createTime=null, userType=null, searchValue=null, status=null}
5.3 集合之间的相互拷贝
public static void main(String[] args) {
List<SysRole> roles = new ArrayList<>(){{
add(new SysRole(1234L));
add(new SysRole(123111L));
}};
List<SysRole> sysRoles = BeanCopyUtils.copyList(roles, SysRole.class);
System.out.println(sysRoles);
}
运行结果
[SysRole(roleId=1234, roleName=null, roleKey=null, roleSort=null, dataScope=null, menuCheckStrictly=null, deptCheckStrictly=null, status=null, delFlag=null, remark=null, flag=false, menuIds=null, deptIds=null), SysRole(roleId=123111, roleName=null, roleKey=null, roleSort=null, dataScope=null, menuCheckStrictly=null, deptCheckStrictly=null, status=null, delFlag=null, remark=null, flag=false, menuIds=null, deptIds=null)]
今天深拷贝就给大家分享到这里,希望大家多多点赞支持,也希望我的分享能给大家的工作和学习带来帮助!!!