深拷贝与浅拷贝-附深拷贝工具类

发布于:2024-04-26 ⋅ 阅读:(26) ⋅ 点赞:(0)

深拷贝与浅拷贝的区别

浅拷贝只是拷贝了源对象的地址,所以当源对象发生改变时,拷贝的对象的值也会对应发生改变。 深拷贝则是拷贝了源对象的所有值,而不是地址,所以深拷贝对象中的值不会随着源对象中的值的改变而改变。

浅拷贝只是拷贝了源对象的地址,所以当源对象发生改变时,拷贝的对象的值也会对应发生改变!!!这块儿要注意,有坑!

 发生的场景

当如果要拷贝一个A对象,而A对象中又有一个B对象,那么如果对A拷贝的时候,重新拷贝出来一个A1对象并且重新分配内存地址, 但是对于A中的B对象,仅仅只是把A1中拷贝出来的B1对象的引用指向原来的B对象而已, 并没有把拷贝的B1对象也重新进行分配一个新的内存地址。这就是浅拷贝。 而深拷贝就是在第1的基础上,不仅重新给A1对象分配了新的内存地址,而且还给A1中的B1也重新进行分配了新的内存地址, 而不只是仅仅把原本的B的引用给B1。这就是深拷贝。

最基本的实现实现 

如果要深拷贝一个对象,那么这个对象必须要实现 Cloneable 接口,实现 重写clone()方法, 并且在 clone 方法内部,把该对象引用的其他对象也要 clone 一份, 这就要求这个被引用的对象必须也要实现Cloneable 接口并且实现 clone 方法 

利用反射机制实现

public static void copy(Object source, Object dest) throws Exception {
    Class destClz = dest.getClass();

    // 获取目标的所有成员
    Field[] destFields = destClz.getDeclaredFields();
    Object value;
    for (Field field : destFields) { // 遍历所有的成员,并赋值
        // 获取value值
        value = getVal(field.getName(), source);

        field.setAccessible(true);
        field.set(dest, value);
    }
}


private static Object getVal(String name, Object obj) throws Exception {
    try {
        // 优先获取obj中同名的成员变量
        Field field = obj.getClass().getDeclaredField(name);
        field.setAccessible(true);
        return field.get(obj);
    } catch (NoSuchFieldException e) {
        // 表示没有同名的变量
    }

    // 获取对应的 getXxx() 或者 isXxx() 方法
    name = name.substring(0, 1).toUpperCase() + name.substring(1);
    String methodName = "get" + name;
    String methodName2 = "is" + name;
    Method[] methods = obj.getClass().getMethods();
    for (Method method : methods) {
        // 只获取无参的方法
        if (method.getParameterCount() > 0) {
            continue;
        }

        if (method.getName().equals(methodName)
                || method.getName().equals(methodName2)) {
            return method.invoke(obj);
        }
    }

    return null;
}

 直接上BeanUtil工具类型

package com.bboss.common.util;

import com.github.dozermapper.core.DozerBeanMapperBuilder;
import com.github.dozermapper.core.Mapper;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.cglib.core.Converter;
import org.springframework.util.ObjectUtils;

import java.lang.ref.SoftReference;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

public class BeanUtil {

    /*
     * 创建默认的DozerBeanMapper
     */
    private static Mapper beanMapper = DozerBeanMapperBuilder.buildDefault();

    /*
     * BeanCopier的类型缓存map
     */
    private static final ConcurrentHashMap<String, SoftReference<BeanCopier>> BEAN_COPIER_CACHE = new ConcurrentHashMap<>();

    /**
     * @description 生成key
     * @param srcClazz 源文件的class
     * @param tgtClazz 目标文件的class
     * @return string
     * @author yanb
     * @date 2020/8/01
     */
    private static String generateKey(Class<?> srcClazz, Class<?> tgtClazz) {
        StringBuilder sb=new StringBuilder(srcClazz.getName()).append(":").append(tgtClazz.getName());
        return sb.toString().intern();
    }

    /**
     * bean对象(属性)拷贝
     * 浅拷贝,高性能
     * @param source 源对象
     * @param target 目标对象
     * @descriptio BeanCopier的copy
     * @author yanb
     * @date 2020/8/01
     */
    public static void copy(Object source, Object target) {
        copy(source, target, null);
    }

    /**
     * 支持自定义converter的拷贝方法
     * 浅拷贝,高性能
     */
    public static void copy(Object source, Object target, Converter converter) {
        if (Objects.isNull(source) || Objects.isNull(target)) {
            return;
        }
        String key = generateKey(source.getClass(), target.getClass());
        BeanCopier beanCopier;
        if (Objects.isNull(BEAN_COPIER_CACHE.get(key))
                || Objects.isNull(beanCopier = BEAN_COPIER_CACHE.get(key).get())) {
            synchronized (key) {
                if (Objects.isNull(BEAN_COPIER_CACHE.get(key))
                        || Objects.isNull(beanCopier = BEAN_COPIER_CACHE.get(key).get())) {
                    beanCopier = BeanCopier.create(source.getClass(), target.getClass(), Objects.nonNull(converter));
                    BEAN_COPIER_CACHE.put(key, new SoftReference<>(beanCopier));
                }
            }
        }
        beanCopier.copy(source, target, converter);
    }

    /* ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ 上面是浅拷贝方法 ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ */

    /* ●▂● ●▂● ●▂● ●▂● ●▂● ●▂● ●▂● ●▂● ●▂● ●▂● ●▂● 华丽的分割线 ●▂● ●▂● ●▂● ●▂● ●▂● ●▂● ●▂● ●▂● ●▂● ●▂● ●▂● */

    /* ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ 下面是深拷贝方法 ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ */

    /**
     * List拷贝,直接返回list对象
     * 深拷贝
     * @param source 源对象
     * @param destinationClass 目标类型
     * @return java.util.List<U>
     * @author yanb
     * @date 2020/8/01
     */
    public static <T, U> List<U> mapList(final List<T> source, final Class<U> destinationClass) {
        if (Objects.isNull(source) || Objects.isNull(destinationClass)) {
            return null;
        }
        final List<U> dest = new ArrayList<U>();
        for (T element : source) {
            dest.add(beanMapper.map(element, destinationClass));
        }
        return dest;
    }

    /**
     * Collection拷贝,直接返回Collection对象
     * 深拷贝
     * @param source 源对象
     * @param destinationClass 目标类型
     * @return java.util.List<U>
     * @author yanb
     * @date 2020/8/01
     */
    public static <T, U> Collection<U> mapCollection(final Collection<T> source, final Class<U> destinationClass) {
        if (Objects.isNull(source)||Objects.isNull(destinationClass)) {
            return null;
        }
        final Collection<U> dest = new ArrayList<>();
        for (T element : source) {
            dest.add(beanMapper.map(element, destinationClass));
        }
        return dest;
    }

    /**
     * 单个对象的 深拷贝
     * 生成新的对象
     * @param source 源对象
     * @param destinationClass 目标类型
     * @return U
     * @author yanb
     * @date 2021/3/17
     */
    public static  <T, U> U deepCopy(final T source, Class<U> destinationClass) {
        if (Objects.isNull(source) || Objects.isNull(destinationClass)){
            return null;
        }
        return beanMapper.map(source, destinationClass);
    }

    /**
     * 单个对象的 深拷贝
     * @param source 源对象
     * @param target 目标对象
     * @return void
     * @author yanb
     * @date 2021/3/17
     */
    public static <U> void deepCopy(Object source, Object target) {
        if (Objects.isNull(source) || Objects.isNull(target)) {
            return;
        }
        beanMapper.map(source, target);
    }

    public static boolean allFieldIsNULL(Object o) {
        try {
            Field[] var1 = o.getClass().getDeclaredFields();
            int var2 = var1.length;

            for(int var3 = 0; var3 < var2; ++var3) {
                Field field = var1[var3];
                field.setAccessible(true);
                Object object = field.get(o);
                if (object instanceof CharSequence) {
                    if (!ObjectUtils.isEmpty(object)) {
                        return false;
                    }
                } else if (null != object) {
                    return false;
                }
            }
        } catch (Exception var6) {
        }

        return true;
    }

}

直接调用上面工具类中的mapList

List<CustBlack>  custBlacksCopy = BeanUtil.mapList(custBlacks,CustBlack.class);