什么是浅拷贝、深拷贝

在计算机内存中,每一个对象都有一个地址,这个地址指向对象在内存中存储的位置。当我们使用变量引用一个对象时,实际上是将该对象的地址赋值给变量。

在Java中生成一个对象 User user = new User(); 这个过程可以分三个步骤

  1. 创建User user的变量
  2. 创建User对象存放到内存中
  3. 将User存放在内存的地址赋值给user变量。可以将user当成一个指针,指向了User对象
    image.png

浅拷贝是创建了一个新的变量,该变量指向了对象的地址,这两个变量共享了同一个内存地址。因此如果修改了复制对象中的属性和元素,原始对象中的对应属性和元素也会被修改

image.png

深拷贝是创建了一个新的变量,同时创建新的空间将原对象数据复制,新变量指向了新开辟出来的对象地址。如果修改了复制对象中的属性和元素,原始对象中的对应属性和元素不会受到影响。

image.png

扩展知识
浅拷贝常用方式
BeanUtils.copyProperties(Object source, Object target) spring工具包下
,通过反射实现
BeanUtils.copyProperties(Object dest, Object orig) apache.commons包下
,通过反射实现

BeanCopier beanCopier = BeanCopier.create(Class source, Class target, boolean useConverter);
beanCopier.copy(source, target, null); (spring包下,通过cglib实现)

深拷贝常用方式
JSON.parseObject(JSON.toJSONString(object), T.class); fastjson包,将对象转化为JSON字符串,然后在转成目标对象

SerializationUtils.clone() apache.commons.lang3包下,将对象先转化为流,在转化为目标对象。该对象必须实现Serializable接口,否则将抛出SerializationException异常。

封装的工具类
fastjson

public class ObjectTransformUtil {

    /**
     * 将给定对象转化为目标对象
     *
     * @param obj         需要转化的对象
     * @param targetClazz 目标对象
     * @return 目标对象
     * @Author wangwei
     * @Date 2021/4/2
     */
    public static <S, T> T transfer(S obj, Class<T> targetClazz) {
        return JSON.parseObject(JSON.toJSONString(obj), targetClazz);
    }

    /**
     * 使用指定的日期格式化规则来转化对象
     *
     * @param obj         需要转化的对象
     * @param targetClazz
     * @param dataFormat
     * @param <S>
     * @param <T>
     * @return
     * @Author wangwei
     * @Date 2021/4/2
     */
    public static <S, T> T transferWithDataFormat(S obj, Class<T> targetClazz, String dataFormat) {
        return JSON.parseObject(JSON.toJSONStringWithDateFormat(obj, dataFormat, SerializerFeature.WriteDateUseDateFormat), targetClazz);
    }

    /**
     * 将集合转化为目标对象
     *
     * @param list        需要转化的对象
     * @param targetClazz 目标对象
     * @return 目标对象
     * @Author wangwei
     * @Date 2021/4/2
     */
    public static <S, T> List<T> transferList(List<S> list, Class<T> targetClazz) {
        if (list == null || list.isEmpty()) {
            return null;
        }
        return JSON.parseArray(JSON.toJSONString(list), targetClazz);
    }

}

BeanCopier

public class BeanCopierUtil {
    /**
     * BeanCopier的缓存,避免频繁创建,高效复用
     */
    private static final ConcurrentHashMap<String, BeanCopier> BEAN_COPIER_MAP_CACHE = new ConcurrentHashMap<String, BeanCopier>();

    /**
     * BeanCopier的copyBean,高性能推荐使用,增加缓存
     *
     * @param source 源文件的
     * @param target 目标文件
     */
    public static void copyBean(Object source, Object target) {
        String key = genKey(source.getClass(), target.getClass());
        BeanCopier beanCopier;
        if (BEAN_COPIER_MAP_CACHE.containsKey(key)) {
            beanCopier = BEAN_COPIER_MAP_CACHE.get(key);
        } else {
            beanCopier = BeanCopier.create(source.getClass(), target.getClass(), false);
            BEAN_COPIER_MAP_CACHE.put(key, beanCopier);
        }
        beanCopier.copy(source, target, null);
    }

    /**
     * 不同类型对象数据copylist
     *
     * @param sourceList
     * @param targetClass
     * @param <T>
     * @return
     */
    public static <T> List<T> copyListProperties(List<?> sourceList, Class<T> targetClass) throws Exception {
        if (ObjectUtil.isNotEmpty(sourceList)) {
            List<T> list = new ArrayList<T>(sourceList.size());
            for (Object source : sourceList) {
                T target = copyProperties(source, targetClass);
                list.add(target);
            }
            return list;
        }
        return Lists.newArrayList();
    }

    /**
     * 返回不同类型对象数据copy,使用此方法需注意不能覆盖默认的无参构造方法
     *
     * @param source
     * @param targetClass
     * @param <T>
     * @return
     */
    public static <T> T copyProperties(Object source, Class<T> targetClass) throws Exception {
        T target = targetClass.newInstance();
        copyBean(source, target);
        return target;
    }

    /**
     * @param srcClazz 源class
     * @param tgtClazz 目标class
     * @return string
     */
    private static String genKey(Class<?> srcClazz, Class<?> tgtClazz) {
        return srcClazz.getName() + tgtClazz.getName();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值