当前位置: 首页 > article >正文

手写一个深拷贝工具

背景

在面向对象编程中,对象之间的复制是一个常见的需求。对象的复制通常分为浅拷贝(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);
    }
}

http://www.kler.cn/a/407817.html

相关文章:

  • 软件测试面试之常规问题
  • 遗传算法(Genetic Algorithm, GA)
  • 探索 .NET 9 控制台应用中的 LiteDB 异步 CRUD 操作
  • Ubuntu24.04普通安装mysql
  • Java集合分页
  • macOS 无法安装第三方app,启用任何来源的方法
  • 【Java知识】Java进阶-web应用热部署
  • 部署端侧大模型
  • 设计模式学习[9]---模板方法模式
  • 深度学习:GPT-1的MindSpore实践
  • git如何将当前的修改提交到其它分支
  • 性能测试调优之线程池的性能优化
  • Spark SQL操作
  • 文件分片上传
  • ubuntu, 安装部署comfyui,记录2:下载模型GGuf及测试
  • 解锁 ChatGPT 超强交互:超级提示词的魔力
  • C#中的二维数组的应用:探索物理含义与数据结构的奇妙融合
  • I.MX6U 裸机开发15.IRQ中断——GPIO中断处理
  • 《FreeRTOS任务删除篇》
  • 第二十九章 TCP 客户端 服务器通信 - 记录的拼接
  • linux下i2c开发与框架源码分析
  • 如何利用java爬虫获得淘宝商品评论
  • 网络安全(骇客)—技术学习
  • 【案例分享】图表工具TeeChart在环境研究领域的数据可视化应用
  • vue前端下载某一区域为照片格式
  • leetcode - 1861. Rotating the Box