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

深拷贝与浅拷贝的区别

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

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

 发生的场景

当如果要拷贝一个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);

  • 11
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: Java中实现深拷贝需要考虑到对象的序列化和反序列化,下面是一个使用Java序列化实现深拷贝工具类代码示例: ``` import java.io.*; public class DeepCopyUtil { public static <T extends Serializable> T deepCopy(T obj) throws IOException, ClassNotFoundException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(obj); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return (T) ois.readObject(); } } ``` 使用示例: ``` public class Main { public static void main(String[] args) throws IOException, ClassNotFoundException { List<Integer> list1 = new ArrayList<>(); list1.add(1); list1.add(2); list1.add(3); List<Integer> list2 = DeepCopyUtil.deepCopy(list1); System.out.println("list1 == list2: " + (list1 == list2)); // false System.out.println("list1.equals(list2): " + list1.equals(list2)); // true } } ``` 该工具类使用了Java的序列化和反序列化,通过将对象序列化成字节数组,再反序列化成新的对象,从而实现了深拷贝。需要注意的是,被复制的对象必须是可序列化的。 ### 回答2: Java中的深拷贝工具类主要用于在创建对象副本时,将对象的所有属性值及其相关的对象也进行拷贝,从而保证新对象的独立性。实现深拷贝的常用方法有两种:序列化与反序列化、自定义深拷贝方法。 首先,使用序列化与反序列化可以实现深拷贝。通过将对象写入流并从流中读取,可以获得该对象的副本。首先,将对象写入OutputStream,再通过ByteArrayInputStream将流转化为字节数组。然后,通过ObjectInputStream将字节数组转化为对象并返回。 其次,可以自定义深拷贝方法。该方法通过递归遍历对象的所有属性,对每个属性实施拷贝操作。如果属性为基本类型,则直接拷贝;如果为引用类型,则递归进行深拷贝。这样可以确保新对象的每个属性都是独立的。 需要注意的是,在使用自定义深拷贝方法时,需要手动实现所有需要拷贝的属性的拷贝逻辑。如果对象的属性过多或复杂,手动实现深拷贝可能会较为繁琐。 综上所述,Java中的深拷贝工具类可以通过序列化与反序列化或自定义深拷贝方法来实现。根据具体需求和对象属性的复杂程度,可以选择合适的方法来完成对象的深拷贝操作。 ### 回答3: Java深拷贝工具类是一个用于复制对象的工具类深拷贝的概念是指在复制对象时,不仅复制对象本身,还复制对象所引用的其他对象,从而实现完全独立的副本。 在实现深拷贝工具类时,可以通过以下步骤: 1. 首先,需要确保被复制的对象及其引用的对象都实现了Cloneable接口,这样才能使用Object类的clone()方法进行对象的浅拷贝。 2. 创建一个新的空对象,用于存储复制后的对象。 3. 遍历被复制的对象的所有引用类型属性或集合,并逐一进行深拷贝。 4. 对于引用类型属性,可以通过递归调用深拷贝方法,将引用对象复制到新的对象中。 5. 对于集合类型属性,可以创建一个新的集合对象,并将原集合中的每个元素进行深拷贝后添加到新的集合中。 6. 最终返回复制后的对象。 需要注意的是,深拷贝工具类只能完成基本数据类型和引用类型的深拷贝,对于对象内部的静态变量或其他逻辑复杂的情况,需要额外的处理方式。 总之,通过深拷贝工具类,我们可以实现对Java对象及其引用对象的完全独立复制,确保原对象和复制对象之间的数据隔离,适用于需要保护原有数据的场景,如多线程环境下的数据处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值