什么是深拷贝和浅拷贝?

news2024/11/18 21:33:09

面试回答

在计算机内存中,每个对象都有一个地址,这个地址指向对象在内存中存储的位置。当我们使用变量引用一个对象时,实际上是将该对象的地址赋值给变量。因此,如果我们将一个对象复制到另一个变量中国,实际上是将对象的地址复制到了这个变量中。

浅拷贝是指将一个对象复制到另一个变量中,但是只复制对象的地址,而不是对象本身。也就是说,原始对象和复制对象实际上是共享同一个内存地址的。因此,如果我们修改了复制对象中的属性或元素,原始对象中对应的属性或元素也会被修改。

未命名表单.png

在 java 中,我们常用的各种 BeanUtils 基本也都是浅拷贝的。

深拷贝是指将一个对象及其所有子对象都复制到另一个变量中,也就是说,它会创建一个全新的对象,并将原始对象中的所有属性或元素都复制到新的对象中。因此,如果我们修改复制对象中的属性或者元素,原始对象中对应的属性或元素不会受到影响。

未命名表单.png

知识扩展

BeanUtils 的浅拷贝

我们举个实际例子,来看下为啥前面说 BeanUtils.copyProperties 的过程是浅拷贝。

先来定义两个类:

@Data
public class Address {
    private String province;
    private String city;
    private String area;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private String name;
    private String password;
    private Address address;
}

然后写一段测试代码:

    public static void main(String[] args) {
        User user=new User();
        user.setName("Tango");
        user.setPassword("123456");
        user.setAddress(new Address("anhui","hefei","shushan"));

        User newUser=new User();
        BeanUtils.copyProperties(user,newUser);

        System.out.println(user==newUser);
        System.out.println(user.getAddress()==newUser.getAddress());
    }

以上代码输出结果为:

false
true

即,我们 BeanUtils.copyProperties拷贝出来的 newUser 是一个新的对象,但是,其中的 address 对象和原来 user 中的 address 对象是同一个对象。

如果我们修改 newUser 中的 address 对象的值的话,是会同时把 user对象中的 address 的值也修改了的。可以尝试着修改下 newUseraddress 对象。

    newUser.getAddress().setCity("beijing");
    System.out.println(JSON.toJSONString(user));
    System.out.println(JSON.toJSONString(newUser));

输出结果:

{"address":{"area":"shushan","city":"beijing","province":"anhui"},"name":"Tango","password":"123456"}
{"address":{"area":"shushan","city":"beijing","province":"anhui"},"name":"Tango","password":"123456"}

实现深拷贝

如何实现深拷贝呢,主要有以下几个方法:

实现 Cloneable 接口,重写 clone()

Object 类中定义了一个 clone 方法,这个方法其实在不重写的情况下,其实也是浅拷贝的。

如果想要实现深拷贝,就需要重写 clone 方法,而想要重写 clone 方法,就必须实现 Cloneable,否则会报 CloneNotSupportedException 异常。

将上诉代码修改下,重写 clone 方法:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Address implements Cloneable{

    private String province;
    private String city;
    private String area;


    @Override
    public Address clone() {
        try {
            Address clone = (Address) super.clone();
            return clone;
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }
}

@Data
public class User implements Cloneable {

    private String name;
    private String password;
    private Address address;

    @Override
    public User clone() {
        try {
            User clone = (User) super.clone();
            clone.setAddress(address.clone());
            return clone;
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }
}

之后,在执行一下下面的测试代码,就可以发现,这时候 newUser 中的 address 对象就是一个新的对象了。如果我们修改 newUser 中的 address 对象的值的话, user对象中的 address 的值是不会被修改的。

    public static void main(String[] args) {
        User user=new User();
        user.setName("Tango");
        user.setPassword("123456");
        user.setAddress(new Address("anhui","hefei","shushan"));

        User newUser=user.clone();

        System.out.println(user==newUser);
        System.out.println(user.getAddress()==newUser.getAddress());

        newUser.getAddress().setCity("beijing");
        System.out.println(JSON.toJSONString(user));
        System.out.println(JSON.toJSONString(newUser));
    }

输出结果:

false
false
{"address":{"area":"shushan","city":"hefei","province":"anhui"},"name":"Tango","password":"123456"}
{"address":{"area":"shushan","city":"beijing","province":"anhui"},"name":"Tango","password":"123456"}

这种方式就能实现深拷贝,但是问题是如果我们在 User 中有很多个对象,那么 clone 方法就写的很长,而且如果后面有修改,在 User 中新增属性,这个地方也要修改。

那么,有没有什么办法可以不需要修改,一劳永逸呢?

序列化实现深拷贝

我们可以借助序列化来实现深拷贝。先把对象序列化成流,再从流中反序列化成对象,这样就一定是新的对象了。序列化的方式有很多,比如我们可以使用各种 JSON 工具,把对象序列化成 JSON 对象,然后再从字符串中反序序列化成对象。

如果使用 fastjson 实现:

User newUser =JSON.parseObject(JSON.toJSONString(user),User.class);

也可以实现深拷贝。

除此之外,还可以使用 org.springframework.util 中提供的 SerializationUtils 工具实现。

我们需要修改下上面的 User 和 Address 类,使他们实现 Serializable接口,否则是无法进行序列化的。

public class Address implements Serializable
public class User  implements Serializable

然后再需要拷贝的时候:

User newUser = (User) SerializationUtils.deserialize(SerializationUtils.serialize(user));

同样,也可以实现深拷贝啦~!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/919919.html

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

相关文章

win11出现安全中心空白和IT管理员已限制对此应用的某些区域的访问

问题 windows安全中心服务被禁用 winr 输入services.msc 找到windows安全中心服务查看是否被禁用,改为启动,不可以改动看第三条 打开设置,找到应用—windows安全中心–终止–修复–重置 重启如果还是不行看第四条 家庭版系统需要打开gped…

SpringBoot整合Mybatis 简单试用

1. 导入依赖 我使用MySQL&#xff0c;需要导入MySQL的驱动依赖此外要在SpringBoot中使用Mybatis&#xff0c;则需要导入Mybatis启动器 <dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifact…

wazuh环境配置及案例复现

文章目录 wazuh环境配置及案例复现wazuh环境配置 案例复现 wazuh环境配置及案例复现 wazuh环境配置 进入官网下载ova软件 https://documentation.wazuh.com/current/deployment-options/virtual-machine/virtual-machine.html 打开下载的ova&#xff0c;密码和用户名会显示…

帆软报表系统未授权查看访问内网ip

子禽问于子贡曰&#xff1a;“夫子至于是邦也&#xff0c;必闻其政&#xff0c;求之与&#xff1f;抑与之与&#xff1f;”子贡曰&#xff1a;“夫子温、良、恭、俭、让以得之。夫子之求之也&#xff0c;其诸异乎人之求之与&#xff01;” 漏洞复现 未授权查看访问内网ip 构…

stm32之4.时钟体系

3.时钟体系(给单片机提供一个非常稳定的频率信号) ①可以使用三种不同的时钟源来驱动系统时钟&#xff08;SYSCLK&#xff09;&#xff0c;CPU运行的频率为168MHZ&#xff1b; HSI(RC振荡器时钟&#xff0c;也就是高速内部时钟&#xff0c;一般来说很少用&#xff0c;因为精度…

服务器基础

基础 介绍 可以理解为企业级的电脑&#xff0c;比个人使用的电脑具备更强的配置、性能、可靠性及稳定性。设计工艺和器件全部采用企业级设计&#xff0c;保障7*24小时稳定运行。 演进历史 处理性能 外观 发展方向 分类 按外形分类 按高度分类 按应用分类 按综合能力分类…

29款影音娱乐-视频类应用评测体验报告

为方便开发者更好地衡量APP在同类产品中的表现和竞争力&#xff0c;有针对性地进行产品优化&#xff0c;软件绿色联盟策划了垂类APP评测体验专题&#xff0c;目前已发布了天气类、小说类、教育学习类APP评测体验报告&#xff0c;本期将对影音娱乐类中的视频类APP围绕绿标五大标…

stm32入门

stm32是基于ARM内核框架的&#xff0c;ARM的发展如下所示。 stm32的基本信息。 stm32的命名规则。 有关GPIO。&#xff08;STM32 GPIO 详解_stm32gpio_天地神仙的博客-CSDN博客&#xff09; 实际例子。 led.h #ifndef _led_H #define _led_H#include "system.h"/* …

0103水平分片-jdbc-shardingsphere-中间件

文章目录 1 准备服务器1.1 创建server-order0容器1.2 创建server-order1容器 2、基本水平分片2.1、基本配置2.2、数据源配置2.3、标椎分片表配置2.4、行表达式2.5、分片算法配置2.6、分布式序列算法 3、多表关联3.1、创建关联表3.2、创建实体类3.3、创建Mapper3.4、配置关联表3…

IDEA项目实践——springMVC概述

系列文章目录 动力节点Java项目的开发原则与核心业务介绍 IDEA项目实践——JavaWeb简介以及Servlet编程实战 IDEA项目实践——Spring当中的切面AOP IDEA项目实践——Spring框架简介&#xff0c;以及IOC注解 IDEA项目实践——动态SQL、关系映射、注解开发 IDEWA项目实践—…

WPF 查看绑定错误——Snoop 的基本使用

关于 可以通过 Snoop 查看 WPF 程序的 Visual Tree&#xff0c;更多介绍请看 snoopwpf 快速开始 一、下载 snoopwpf.msi 安装后打开&#xff0c;选择自己的程序&#xff0c;点击 snoop&#xff08;望远镜&#xff09; 二、筛选 点击左侧下拉列表&#xff0c;选择 Show onl…

Spring框架中的Singleton和Prototype Bean作用域

Spring框架是依赖注入的事实上的框架&#xff0c;在开发可扩展、弹性和安全的云原生环境中具有良好的记录。 在使用Spring Beans时&#xff0c;初学者经常会对Spring beans和它们的作用域感到有些困惑。 以下是我对Singleton和Prototype Bean作用域的简单示例进行阐述的尝试。 …

Midjourney API 的对接和使用

“ 阅读本文大概需要 4 分钟。 ” 在人工智能绘图领域&#xff0c;想必大家听说过 Midjourney 的大名吧。 Midjourney 以其出色的绘图能力在业界独树一帜。无需过多复杂的操作&#xff0c;只要简单输入绘图指令&#xff0c;这个神奇的工具就能在瞬间为我们呈现出对应的图像。无…

C#实现简单TCP服务器和客户端网络编程

在C#中进行网络编程涉及许多类和命名空间&#xff0c;用于创建和管理网络连接、传输数据等。下面是一些主要涉及的类和命名空间&#xff1a; System.Net 命名空间&#xff1a;这个命名空间提供了大部分网络编程所需的类&#xff0c;包括&#xff1a; IPAddress&#xff1a;用于…

2.IO控制器

第五章 I/O管理 2.I/O控制器 I/O控制器的组成&#xff1a; I/O控制器负责接收和识别从CPU发来的各种命令&#xff0c;同时需要翻译为具体的设备可以明白的命令&#xff0c;通过控制器与设备的接口发送给具体的设备&#xff0c;让设备执行相应的操作。 一个I/O控制器有可能会负…

跨越边界:从前端切图仔走进iOS开发(Swift版--上集)

本文简介 点赞 关注 收藏 学会了 本文将以前端开发者的视角&#xff0c;和各位工友进入iOS开发的世界。 本文以实战为导向&#xff0c;快速掌握iOS开发这个技能。 无论你是想要扩展技能领域&#xff0c;还是对iOS开发充满好奇&#xff0c;花一个下午学习本文都能打开iOS开…

AUTOSAR规范与ECU软件开发(实践篇)5.6 基于ISOLAR-A的系统级设计与配置方法(下)

目录 3 、系统配置 4、 ECU信息抽取 3 、系统配置 在完成了VehicleComposition建立后, 可以进行系统配置。 右键点击System→Create System Info→Elements|System(图5.83) 可以新建System Info, 命名为VehicleSystem, 结果如图5.84所示。 图5.83 System Info新建(一)

Unity 3D之 利用Vector3 计算移动方向,以及实现位移多少

文章目录 先分析代码&#xff0c;从代码中了解Vector3 moveDirection new Vector3(10f, 0f, 100f);合法吗Vector3 moveDirection new Vector3 (xf,yf,zf)不是用来表示三维坐标的怎么表示在某个方向的位移 先分析代码&#xff0c;从代码中了解 这段代码是一个在游戏开发中常见…

回归预测 | MATLAB实现DBN-ELM深度置信网络结合极限学习机多输入单输出回归预测

回归预测 | MATLAB实现DBN-ELM深度置信网络结合极限学习机多输入单输出回归预测 目录 回归预测 | MATLAB实现DBN-ELM深度置信网络结合极限学习机多输入单输出回归预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 1.MATLAB实现DBN-ELM深度置信网络结合极限学习…

七夕学算法

目录 P1031 [NOIP2002 提高组] 均分纸牌 原题链接 : 题面 : 思路 : 代码 : P1036 [NOIP2002 普及组] 选数 原题链接 : 题面 : 思路 : 代码 : P1060 [NOIP2006 普及组] 开心的金明 原题链接 : 题面 : 思路 : 01背包例题 : 代码 : P1100 高低位交换 原题…