深拷贝是我们在代码开发当中经常需要使用到的,但是市面上的对象拷贝方法,比如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)]
今天深拷贝就给大家分享到这里,希望大家多多点赞支持,也希望我的分享能给大家的工作和学习带来帮助!!!


















