手写一个深拷贝工具

背景

在面向对象编程中,对象之间的复制是一个常见的需求。对象的复制通常分为浅拷贝(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 Setterspublic 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; }@Overridepublic String toString() {return "NestedObjectA{" +"id=" + id +", name='" + name + '\'' +'}';}
}// 嵌套对象 B
public class NestedObjectB {private double value;private NestedObjectA nestedObjectA;// Getters and Setterspublic 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; }@Overridepublic 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 Setterspublic 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; }@Overridepublic 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 Setterspublic 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; }@Overridepublic 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.mzph.cn/pingmian/61746.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Node.js的下载与安装(支持各种新旧版本)

目录 1、node官网 2、node软件下载 3、软件安装&#xff08;完整版&#xff09; 1、node官网 Node.js — Download Node.jshttps://nodejs.org/en/download/package-manager 2、node软件下载 按照下图进行选择node版本&#xff08;真心推荐16/18&#xff0c;而是尽量是LTS…

对于相对速度的重新理解 - 2

回到先前说的&#xff0c;先令真空光速为标准光速&#xff0c; 光子的绝对速度 范围&#xff0c; 物质粒子的 范围&#xff0c; 这样的话&#xff0c;我们就可以根据 和 &#xff0c;把速度分成3个段&#xff0c; 这样就可以出现速度和它的负值&#xff0c;也就是速度的矢量具…

大模型系列11-ray

大模型系列11-ray PlasmaPlasmaStore启动监听处理请求 ProcessMessagePlasmaCreateRequest请求PlasmaCreateRetryRequest请求PlasmaGetRequest请求PlasmaReleaseRequestPlasmaDeleteRequestPlasmaSealRequest ObjectLifecycleManagerGetObjectSealObject ObjectStoreRunnerPlas…

Java---反射机制

JAVA反射机制是在运行状态中&#xff0c;对于任意一个类&#xff0c;都能够知道这个类的所有属性和方法&#xff1b;对于任意一个对象&#xff0c; 都能够调用它的任意方法和属性&#xff1b;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。 在编译后产生…

Java 线程状态详解

1 引言 在 Java 多线程编程中&#xff0c;线程的状态是一个非常重要的概念。了解线程的状态及其转换过程&#xff0c;有助于我们更好地理解和控制线程的行为。本文将详细介绍 Java 线程的 6 种状态&#xff0c;并通过示例代码和图解来帮助读者更好地理解这些状态及其转换过程。…

AirScreen 安卓平板作为MacOS副屏

前言&#xff1a; 对笔记本续航有刚需&#xff0c;不得不选MacBook。 手机用的是mate40Pro&#xff0c;平板用的是matepad pro 12.6 干货&#xff1a; 参考网友的分享&#xff1a; https://www.bilibili.com/video/BV12A4y1d7zX/?spm_id_from333.337.search-card.all.click 【…

深度强化学习(RL)介绍

深度强化学习&#xff08;RL&#xff09;介绍 写到了一半&#xff0c;图待后补 一、强化学习概述 &#xff08;一&#xff09;与监督学习对比及定义 强化学习不同于监督学习&#xff0c;在一些任务中数据标注困难&#xff0c;但机器可通过环境反馈知道结果好坏。强化学习是机…

使用 Elasticsearch 构建食谱搜索(二)

这篇文章是之前的文章 “使用 Elasticsearch 构建食谱搜索&#xff08;一&#xff09;” 的续篇。在这篇文章中&#xff0c;我将详述如何使用本地 Elasticsearch 部署来完成对示例代码的运行。该项目演示了如何使用 Elastic 的 ELSER 实现语义搜索并将其结果与传统的词汇搜索进…

数据结构 【带环单链表】

在单链表中可能会存在一种情况&#xff0c;某一结点在经过几次转移之后回到了自己本身&#xff0c;这种情况就称之为带环链表。对于带环链表&#xff0c;我们不能轻易对其进行遍历&#xff0c;遍历可能会导致产生死循环。 带环链表的逻辑图如下所示&#xff1a;&#xff08;这…

Vue 项目中如何使用FullCalendar 时间段选择插件(类似会议室预定、课程表)

本文中是基于VUEelementui项目中实现的前后端分离的前端功能部分&#xff1a; 插件的官方文档&#xff1a;FullCalendar 1.安装对应依赖&#xff08;统一安装版本为6.15&#xff09; npm install --save fullcalendar/core6.15 npm install --save fullcalendar/daygrid6.…

学习路之压力测试--jmeter安装教程

Jmeter安装 0、先安装jdk:这里是安装jdk-8u211-windows-x64 1、百度网盘上下载 jdk和jmeter 链接: https://pan.baidu.com/s/1qqqaQdNj1ABT1PnH4hfeCw?pwdkwrr 提取码: kwrr 复制这段内容后打开百度网盘手机App&#xff0c;操作更方便哦 官网&#xff1a;Apache JMeter - D…

SQL99版全外连接和交叉连接和总结

全外连接MySQL不支持 elect 查询列表 from 表名1 表别名1 cross join 表名2 表别名2 on 连接条件 ...... ; 交叉连接 就两个记录做笛卡尔积&#xff01;没什么好说的&#xff0c;基本也没用过&#xff01; 总结

Python爬虫:深入探索1688关键词接口获取之道

在数字化经济的浪潮中&#xff0c;数据的价值愈发凸显&#xff0c;尤其是在电商领域。对于电商平台而言&#xff0c;关键词不仅是搜索流量的入口&#xff0c;也是洞察市场趋势、优化营销策略的重要工具。1688作为中国领先的B2B电商平台&#xff0c;其关键词接口的获取对于商家来…

ffmpeg本地编译不容易发现的问题 — Error:xxxxx not found!

这里区分电脑CPU架构 本次编译是在Mac笔记本&#xff0c;M1芯片上进行&#xff01; 前面大致流程&#xff1a;分为两种&#xff08;1.仅适用&#xff0c;直接下载编译好的本地安装即可&#xff1b;2.使用并查看源码&#xff0c;自己修改编译运行&#xff09;。这里介绍的是第…

从0-1逐步搭建一个前端脚手架工具并发布到npm

前言 本文介绍的案例已同步到github&#xff0c;github地址。 vue-cli 和 create-react-app 等 cli 脚手架工具用于快速搭建应用&#xff0c;无需手动配置复杂的构建环境。本文介绍如何使用 rollup 搭建一个脚手架工具。 脚手架工具的工作流程简言为&#xff1a;提供远端仓库…

摄影:相机控色

摄影&#xff1a;相机控色 白平衡&#xff08;White Balance&#xff09;白平衡的作用&#xff1a; 白平衡的使用环境色温下相机色温下总结 白平衡偏移与包围白平衡包围 影调 白平衡&#xff08;White Balance&#xff09; 人眼看到的白色&#xff1a;会自动适应环境光线。 相…

键盘党福音!自定义指令实现回车快捷删除

前言 &#x1f4eb; 大家好&#xff0c;我是南木元元&#xff0c;热爱技术和分享&#xff0c;欢迎大家交流&#xff0c;一起学习进步&#xff01; &#x1f345; 个人主页&#xff1a;南木元元 目录 确认对话框 回车键快捷确认 自定义指令实现回车删除 实现思路 实现代码 …

AG32既可以做MCU,也可以仅当CPLD使用

Question: AHB总线上的所有外设都需要像ADC一样&#xff0c;通过cpld处理之后才能使用? Reply: 不用。 除了ADC外&#xff0c;其他都是 mcu可以直接配置使用的。 Question: DMA和CMP也不用? Reply: DMA不用。 ADC/DAC/CMP 用。 CMP 其实配置好后&#xff0c;可以直…

深度学习实战人脸识别

文章目录 前言一、人脸识别一般过程二、人脸检测主流算法1. MTCNN2. RetinaFace3. CenterFace4. BlazeFace5. YOLO6. SSD7. CascadeCNN 三、人脸识别主流算法1.deepface2.FaceNet3.ArcFace4.VGGFace5.DeepID 四、人脸识别系统实现0.安装教程与资源说明1. 界面采用PyQt5框架2.人…