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

devtools/2024/9/20 15:35:53/

深拷贝与浅拷贝的区别

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

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

 发生的场景

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


http://www.ppmy.cn/devtools/19319.html

相关文章

【java毕业设计】 基于Spring Boot+mysql的高校心理教育辅导系统设计与实现(程序源码)-高校心理教育辅导系统

基于Spring Bootmysql的高校心理教育辅导系统设计与实现&#xff08;程序源码毕业论文&#xff09; 大家好&#xff0c;今天给大家介绍基于Spring Bootmysql的高校心理教育辅导系统设计与实现&#xff0c;本论文只截取部分文章重点&#xff0c;文章末尾附有本毕业设计完整源码及…

pnpm 安装后 node_modules 是什么结构?为什么 webpack 不识别 pnpm 安装的包?

本篇研究&#xff1a;使用 pnpm 安装依赖时&#xff0c;node_modules 下是什么结构 回顾 npm3 之前&#xff1a;依赖树 缺点&#xff1a; frequently packages were creating too deep dependency trees, which caused long directory paths issue on Windowspackages were c…

【机器学习】农田智能监控系统的实践探索

机器学习赋能现代农业&#xff1a;农田智能监控系统的实践探索 一、机器学习在现代农业中的重要作用二、机器学习在农田智能监控系统中的应用三、农田智能监控系统的实践意义 在科技飞速发展的今天&#xff0c;机器学习技术正以其强大的数据处理和模式识别能力&#xff0c;逐步…

如何有效的将丢失的mfc140u.dll修复,几种mfc140u.dll丢失的解决方法

当你在运行某个程序或应用程序时&#xff0c;突然遭遇到mfc140u.dll丢失的错误提示&#xff0c;这可能会对你的电脑运行产生一些不利影响。但是&#xff0c;不要担心&#xff0c;以下是一套详细的mfc140u.dll丢失的解决方法。 mfc140u.dll缺失问题的详细解决步骤 步骤1&#x…

SV-7041T IP网络有源音箱 教室广播多媒体音箱(带本地扩音功能)教学广播音箱 办公室背景音乐广播音箱 2.0声道壁挂式网络有源音箱

SV-7041T IP网络有源音箱 教室广播多媒体音箱&#xff08;带本地扩音功能&#xff09; 教学广播音箱 办公室背景音乐广播音箱 一、描述 SV-7041T是深圳锐科达电子有限公司的一款2.0声道壁挂式网络有源音箱&#xff0c;具有10/100M以太网接口&#xff0c;可将网络音源通过自带…

DSP开发实战教程-国产DSP替代进口TI DSP的使用技巧

1.替换CCS安装路径下的Flash.out文件 找到各自CCS的安装路径&#xff1a; D:\ti\ccs1230\ccs\ccs_base\c2000\flashAlgorithms 复制进芯电子国产DSP官网提供的配置文件 下载链接&#xff1a;https://mp.csdn.net/mp_download/manage/download/UpDetailed 2.替换原有文件 3.…

MATLAB初学者入门(14)—— 支持向量机

支持向量机&#xff08;SVM&#xff09;是一种强大的分类技术&#xff0c;用于解决分类和回归问题。它工作原理是找到最优的超平面&#xff0c;该超平面能够最大化不同类别数据点之间的边界。MATLAB提供了一个简单易用的工具箱&#xff0c;称为Statistics and Machine Learning…

在Linux系统内搭建DNS本地服务器

文章目录 Linux的本地DNS服务一、什么是DNS1.1、域名1.2、DNS服务器、DNS客户端和DNS中继1.3、DNS域名解析 二、搭建DNS服务2.1、正反向解析2.1.1.安装bind软件包2.1.2.修改主配置文件2.1.3.修改区域配置文件2.1.4.配置区域数据文件2.1.5.启动服务、关闭防火墙2.1.6.本地解析测…

【Pytorch】PytorchCPU版或GPU报错异常处理(10X~4090D)

Pytorch为CPU版或GPU使用报错异常处理 文章目录 Pytorch为CPU版或GPU使用报错异常处理0.检查阶段1. 在conda虚拟环境中安装了torch2.卸载cpuonly3.从tsinghua清华源安装不完善误为cpu版本4.用tsinghua清华源安装成cpu错误版本5.conda中torch/vision/cudatoolkit版本与本机cuda版…

Python编程----递归求解兔子的数量

描述 兔子的数量以这样的方式增长&#xff1a;每个月的兔子数量等于它前一个月的兔子数量加它前两个月的兔子数量&#xff0c;即f(n)f(n-1)f(n-2)。假设第1个月的兔子有2只&#xff0c;第2个月的兔子有3只&#xff0c;你能使用递归的方法求得第n个月的兔子有多少只吗&#xff…

微前端micro-app 子应用 调用父应用方法

参考&#xff1a;micro-app官方文档 场景描述 父应用存储一套vuex数据&#xff0c;其中包含登录信息token等&#xff0c;登录信息透传给子应用使用。 当子应用中的接口返回“登录失效”时&#xff0c;需要清空父应用vuex中的登录相关信息&#xff0c;并且跳转到登录页面。 原…

Nest.js项目小结2

1.配置了项目路径别名 tsconfig.json {"compilerOptions": {"module": "commonjs","declaration": true,"removeComments": true,"emitDecoratorMetadata": true,"experimentalDecorators": true,&quo…

SpringBoot教程(十九) | SpringBoot集成knife4j

首先介绍一下Knife4j. 就是一款接口文档框架&#xff0c;跟swagger类似。 但是整合了很多swagger的功能&#xff0c;页面比swagger美观。现在大有取代swagger之势 官方文档地址&#xff1a; https://doc.xiaominfo.com/docs/quick-start 其实主要的集成方式&#xff0c;在文档…

java中泛型(一)

泛型简介 在之前关于类的学习中我们知道&#xff0c;一个类中可以定义它的属性以及方法&#xff0c;在那里我们定义类的属性时不同的属性我们采用的是不同的数据类型&#xff0c;这就要求我们对每一个数据的类型进行声明操作。但是我们想到这样一个问题&#xff0c;如果这个类有…

持续集成和持续部署(CI/CD)

持续集成&#xff08;Continuous Integration&#xff0c;简称CI&#xff09;和持续部署&#xff08;Continuous Deployment&#xff0c;简称CD&#xff09;是现代软件开发中的重要实践&#xff0c;旨在提高开发团队的效率和软件交付的质量。 持续集成是指开发人员将代码频繁地…

STM32自己从零开始实操01:原理图

在听完老师关于 STM32 物联网项目的所有硬件课程之后&#xff0c;就是感觉自己云里雾里&#xff0c;明明课程都认真听完了&#xff0c;笔记也认真记录&#xff0c;但是就是感觉学到的知识还不是自己。 遂决定站在老师的肩膀上自己开始设计项目&#xff0c;将知识变成自己的&am…

torch.mm函数介绍

torch.mm() 是 PyTorch 中用于执行矩阵乘法&#xff08;matrix multiplication&#xff09;的函数。它能够将两个给定的张量进行矩阵乘法运算&#xff0c;得到结果张量。 这是 torch.mm() 函数的基本语法&#xff1a; torch.mm(input, mat2, *, outNone)input: 第一个输入张量…

【React】CSS 局部样式

书写 CSS 的时候&#xff0c;如果 CSS 文件名包含 module&#xff0c;那么说明该 CSS 是一个局部 CSS 样式文件&#xff0c;类似于 vue 中的 scoped。 .avatarContainer {width: 40px;height: 40px;border-radius: 50%;background: rgb(213, 226, 226); }import styles from ..…

维基百科、百度百科和搜狗百科词条的创建流程

随着网络的发展&#xff0c;百度百科、搜狗百科、维基百科等百科网站已经成为大众获取知识的重要途径。因为百科具有得天独厚的平台优势&#xff0c;百科上的信息可信度高&#xff0c;权威性强。所以百科平台也成为商家的必争之地。这里小马识途聊聊如何创建百度百科、搜狗百科…

基于EMD与LSTM/RNN的时间序列预测方法(Python代码)

采用EMD方法将时间序列进行分解&#xff0c;然后基于样本熵理论对IMF分量进行测量,对高频序列用LSTM预测&#xff0c;对低频序列用RNN预测.神经网络在预测集上采用滚动预测的方法进行。主代码如下&#xff1a; from PyEMD import EMD import pandas as pd import numpy as np …