一个工具类让你彻底解决bean深拷贝

本文介绍了深拷贝和浅拷贝的概念与区别,并提供了一个基于Hutool和Lombok的深拷贝工具类,包括单对象拷贝、列表对象拷贝以及对象与Map之间的转换。此外,文章还通过示例展示了如何使用该工具类进行对象间的拷贝操作。
摘要由CSDN通过智能技术生成

深拷贝是我们在代码开发当中经常需要使用到的,但是市面上的对象拷贝方法,比如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)]

今天深拷贝就给大家分享到这里,希望大家多多点赞支持,也希望我的分享能给大家的工作和学习带来帮助!!!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

技术闲聊DD

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值