手写一个深拷贝工具

背景

在面向对象编程中,对象之间的复制是一个常见的需求。对象的复制通常分为浅拷贝(Shallow Copy)和深拷贝(Deep Copy)两种方式。浅拷贝只复制对象的基本数据类型和引用类型的数据地址,而深拷贝则会递归地复制对象及其引用的所有子对象,确保新对象与原对象完全独立。

深拷贝的重要性在于它可以避免对象之间的相互影响。在实际开发中,如果不正确地处理对象的复制,可能会导致数据不一致、内存泄漏等问题。因此,掌握深拷贝的实现方法对于提高代码质量和系统稳定性具有重要意义。

深拷贝介绍

深拷贝(Deep Copy)是指在复制对象时,不仅复制对象本身,还递归地复制对象中引用的所有子对象。这样可以确保新对象与原对象完全独立,修改新对象不会影响原对象。

浅拷贝的不足

在 Java 中,如果我们简单地使用赋值语句将一个对象赋值给另一个对象,例如:

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // Getters and setters
}

public class Main {
    public static void main(String[] args) {
        Person person1 = new Person("Alice", 25);
        Person person2 = person1;

        person2.setAge(30);

        System.out.println(person1.getAge()); // 输出 30,而不是 25
    }
}

这里,person2 只是 person1 的浅拷贝,它们指向同一个内存地址。当修改 person2 的属性时,person1 的属性也随之改变,因为它们本质上是同一个对象。

深拷贝的应用场景

  1. 多线程环境:在多线程环境中,为了避免多个线程对同一个对象的访问导致的数据不一致问题,可以使用深拷贝来创建独立的对象副本。
  2. 数据备份:在进行数据备份时,深拷贝可以确保备份数据与原始数据完全独立,避免因修改原始数据而影响备份数据。
  3. 历史记录:在需要保存对象的历史状态时,深拷贝可以创建对象的完整副本,以便后续回溯或恢复。
  4. 对象传递:在需要将对象传递给其他方法或模块时,使用深拷贝可以确保传递的是一个独立的副本,避免意外的修改影响原对象。

代码示例

下面是一个使用 Java 反射机制实现深拷贝的示例。这个示例展示了如何将一个复杂的对象深拷贝到另一个对象中,即使这两个对象是不同的类,但具有相同名称和类型的字段。

定义实体类

// 嵌套对象 A
public class NestedObjectA {
    private int id;
    private String name;

    // Getters and Setters
    public int getId() { return id; }
    public void setId(int id) { this.id = id; }

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    @Override
    public String toString() {
        return "NestedObjectA{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

// 嵌套对象 B
public class NestedObjectB {
    private double value;
    private NestedObjectA nestedObjectA;

    // Getters and Setters
    public double getValue() { return value; }
    public void setValue(double value) { this.value = value; }

    public NestedObjectA getNestedObjectA() { return nestedObjectA; }
    public void setNestedObjectA(NestedObjectA nestedObjectA) { this.nestedObjectA = nestedObjectA; }

    @Override
    public String toString() {
        return "NestedObjectB{" +
                "value=" + value +
                ", nestedObjectA=" + nestedObjectA +
                '}';
    }
}

// 源对象
public class SourceObject {
    private int intField;
    private String stringField;
    private List<NestedObjectA> listField;
    private Map<String, NestedObjectB> mapField;

    // Getters and Setters
    public int getIntField() { return intField; }
    public void setIntField(int intField) { this.intField = intField; }

    public String getStringField() { return stringField; }
    public void setStringField(String stringField) { this.stringField = stringField; }

    public List<NestedObjectA> getListField() { return listField; }
    public void setListField(List<NestedObjectA> listField) { this.listField = listField; }

    public Map<String, NestedObjectB> getMapField() { return mapField; }
    public void setMapField(Map<String, NestedObjectB> mapField) { this.mapField = mapField; }

    @Override
    public String toString() {
        return "SourceObject{" +
                "intField=" + intField +
                ", stringField='" + stringField + '\'' +
                ", listField=" + listField +
                ", mapField=" + mapField +
                '}';
    }
}

// 目标对象
public class TargetObject {
    private int intField;
    private String stringField;
    private List<NestedObjectA> listField;
    private Map<String, NestedObjectB> mapField;

    // Getters and Setters
    public int getIntField() { return intField; }
    public void setIntField(int intField) { this.intField = intField; }

    public String getStringField() { return stringField; }
    public void setStringField(String stringField) { this.stringField = stringField; }

    public List<NestedObjectA> getListField() { return listField; }
    public void setListField(List<NestedObjectA> listField) { this.listField = listField; }

    public Map<String, NestedObjectB> getMapField() { return mapField; }
    public void setMapField(Map<String, NestedObjectB> mapField) { this.mapField = mapField; }

    @Override
    public String toString() {
        return "TargetObject{" +
                "intField=" + intField +
                ", stringField='" + stringField + '\'' +
                ", listField=" + listField +
                ", mapField=" + mapField +
                '}';
    }
}

DeepCopyUtil 深拷贝工具类

public class DeepCopyUtil {

    public static void deepCopyFields(Object source, Object target) throws IllegalAccessException {
        Class<?> sourceClass = source.getClass();
        Class<?> targetClass = target.getClass();

        // 获取源对象和目标对象的所有字段
        Field[] sourceFields = getAllFields(sourceClass);
        Field[] targetFields = getAllFields(targetClass);

        // 创建字段名称到字段的映射
        Map<String, Field> targetFieldMap = new HashMap<>();
        for (Field field : targetFields) {
            field.setAccessible(true);
            targetFieldMap.put(field.getName(), field);
        }

        // 遍历源对象的字段
        for (Field sourceField : sourceFields) {
            sourceField.setAccessible(true);
            Object sourceValue = sourceField.get(source);

            // 检查目标对象是否有同名字段
            Field targetField = targetFieldMap.get(sourceField.getName());
            if (targetField != null && sourceField.getType().equals(targetField.getType())) {
                if (isBasicTypeOrWrapperOrString(sourceField.getType())) {
                    // 如果是基本类型或字符串,直接赋值给目标对象的对应字段
                    targetField.set(target, sourceValue);
                } else if (List.class.isAssignableFrom(sourceField.getType())) {
                    // 如果是列表类型,进行列表元素的深拷贝
                    List<?> sourceList = (List<?>) sourceValue;
                    List<Object> targetList = new ArrayList<>();
                    for (Object item : sourceList) {
                        targetList.add(deepCopy(item));
                    }
                    targetField.set(target, targetList);
                } else if (Set.class.isAssignableFrom(sourceField.getType())) {
                    // 如果是集合类型,进行集合元素的深拷贝
                    Set<?> sourceSet = (Set<?>) sourceValue;
                    Set<Object> targetSet = new HashSet<>();
                    for (Object item : sourceSet) {
                        targetSet.add(deepCopy(item));
                    }
                    targetField.set(target, targetSet);
                } else if (Map.class.isAssignableFrom(sourceField.getType())) {
                    // 如果是映射类型,进行映射元素的深拷贝
                    Map<?, ?> sourceMap = (Map<?, ?>) sourceValue;
                    Map<Object, Object> targetMap = new HashMap<>();
                    for (Map.Entry<?, ?> entry : sourceMap.entrySet()) {
                        Object key = deepCopy(entry.getKey());
                        Object value = deepCopy(entry.getValue());
                        targetMap.put(key, value);
                    }
                    targetField.set(target, targetMap);
                } else {
                    // 其他类型进行深拷贝
                    targetField.set(target, deepCopy(sourceValue));
                }
            }
        }
    }

    private static Field[] getAllFields(Class<?> clazz) {
        List<Field> fields = new ArrayList<>();
        while (clazz != null) {
            fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
            clazz = clazz.getSuperclass();
        }
        return fields.toArray(new Field[0]);
    }

    private static boolean isBasicTypeOrWrapperOrString(Class<?> clazz) {
        return clazz.equals(int.class) || clazz.equals(Integer.class) ||
                clazz.equals(long.class) || clazz.equals(Long.class) ||
                clazz.equals(float.class) || clazz.equals(Float.class) ||
                clazz.equals(double.class) || clazz.equals(Double.class) ||
                clazz.equals(boolean.class) || clazz.equals(Boolean.class) ||
                clazz.equals(char.class) || clazz.equals(Character.class) ||
                clazz.equals(byte.class) || clazz.equals(Byte.class) ||
                clazz.equals(short.class) || clazz.equals(Short.class) ||
                clazz.equals(String.class);
    }

    private static Object deepCopy(Object obj) {
        if (obj == null) {
            return null;
        }
        if (isBasicTypeOrWrapperOrString(obj.getClass())) {
            return obj;
        }
        if (obj instanceof List) {
            List<?> sourceList = (List<?>) obj;
            List<Object> targetList = new ArrayList<>();
            for (Object item : sourceList) {
                targetList.add(deepCopy(item));
            }
            return targetList;
        }
        if (obj instanceof Set) {
            Set<?> sourceSet = (Set<?>) obj;
            Set<Object> targetSet = new HashSet<>();
            for (Object item : sourceSet) {
                targetSet.add(deepCopy(item));
            }
            return targetSet;
        }
        if (obj instanceof Map) {
            Map<?, ?> sourceMap = (Map<?, ?>) obj;
            Map<Object, Object> targetMap = new HashMap<>();
            for (Map.Entry<?, ?> entry : sourceMap.entrySet()) {
                Object key = deepCopy(entry.getKey());
                Object value = deepCopy(entry.getValue());
                targetMap.put(key, value);
            }
            return targetMap;
        }
        // 对于其他复杂对象,递归调用 deepCopyFields 方法
        try {
            Object target = obj.getClass().getDeclaredConstructor().newInstance();
            deepCopyFields(obj, target);
            return target;
        } catch (Exception e) {
            throw new RuntimeException("Failed to deep copy object", e);
        }
    }
}

Main方法

 public static void main(String[] args) throws IllegalAccessException {
        // 创建示例对象
        SourceObject source = new SourceObject();
        TargetObject target = new TargetObject();

        // 初始化源对象
        source.setIntField(10);
        source.setStringField("Hello");

        List<NestedObjectA> listField = new ArrayList<>();
        listField.add(new NestedObjectA());
        listField.get(0).setId(1);
        listField.get(0).setName("A1");
        source.setListField(listField);

        Map<String, NestedObjectB> mapField = new HashMap<>();
        NestedObjectB nestedObjectB = new NestedObjectB();
        nestedObjectB.setValue(3.14);
        nestedObjectB.setNestedObjectA(new NestedObjectA());
        nestedObjectB.getNestedObjectA().setId(2);
        nestedObjectB.getNestedObjectA().setName("A2");
        mapField.put("key1", nestedObjectB);
        source.setMapField(mapField);

        // 进行深拷贝
        deepCopyFields(source, target);

        // 输出结果
        System.out.println("Source: " + source);
        System.out.println("Target: " + target);
    }
}
相关推荐
dreamsever几秒前
Glide源码学习
android·java·学习·glide
武昌库里写JAVA1 分钟前
SpringBoot+SpringCloud面试题整理附答案
java·开发语言·算法·spring·log4j
呼啦啦啦啦啦啦啦啦5 分钟前
每日刷题(有效括号序列,滑动窗口最大值,最小的K个数,寻找第K大)
java·前端·javascript
手握风云-7 分钟前
数据结构(Java版)第五期:ArrayList与顺序表(下)
java·数据结构·算法
蜗牛沐雨8 分钟前
Go语言中的sync.Pool详解:高效对象复用
java·jvm·golang
不会玩技术的技术girl17 分钟前
Java爬虫与淘宝API接口:深度解析销量和商品详情数据获取
java·开发语言·爬虫
MG_鹏鹏27 分钟前
SpringBoot实现单文件上传
java·spring boot·spring
除了代码啥也不会1 小时前
springboot 整合 rabbitMQ (延迟队列)
java·分布式·rabbitmq
xq5148631 小时前
内存分配与回收策略
java·开发语言·jvm
cuisidong19971 小时前
springmvc 用了 @RequestMapping 是不是可以不用
java·开发语言