java干货 浅拷贝和深拷贝

文章目录

    • 一、浅拷贝
      • 1.1 特点
      • 1.2 代码实现
    • 二、深拷贝
      • 2.1 特点
    • 三、总结

一、浅拷贝

1.1 特点

  • 基本数据类型字段的拷贝:值被复制,新对象和原对象的字段在内存中是不同
  • 引用类型字段的拷贝:对于引用类型,它们的引用被复制,他们指向同一个内存空间,是同一份数据。
    注意:当引用类型字段发生改变时,不可变引用类型和可变引用类型是不同的,前者是线程安全的,后者是线程不安全的:
    • 如:因为 String 是不可变的,当新对象的String 类型字段 发生变化时,但是原对象的同一String 字段不变。这是因为新对象的String 字段只是指向另一个内存堆空间。如 String a = “123”; String b = a; a = “456”; a 指向的新的内存空间,并不是将“123”所在空间的值改为“456”,这是String 底层使用不可变数组导致的。a 的 改变不会引起b的改变,因此String 是线程安全的

1.2 代码实现

  • 通过构造函数 传递对象 实现浅拷贝 不可变引用类型
class Person {private String name;private int age;// Constructorpublic Person(String name, int age) {this.name = name;this.age = age;}// Copy constructor for shallow copypublic Person(Person other) {this.name = other.name; // Assigning reference of other.name to this.namethis.age = other.age;}// Getters and Setterspublic String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public static void main(String[] args) {Person original = new Person("John", 30);Person copy = new Person(original);System.out.println(original.name == copy.name);// 改变 拷贝对象的 引用类型字段的值copy.setName("Doe");System.out.println(original.name == copy.name);}
}
true
false

分析:对象original 和 copy 的name 字段通过引用赋值,实现浅拷贝,两个对象的name 引用指向同一内存空间。当修改copy 的name 的值后,两者本应该还是指向同一个内存空间,但是实际却不是。这是因为name 是String 类型,String 不可变,给copy 的name 赋 新的值,实际上是开辟了新的内存空间,copy 的name 指向这一个新空间,而 original 还是指向原来那个空间,那个空间的值没变,也不可变。

修改基本类型的值

public static void main(String[] args) {Person original = new Person("John", 30);Person copy = new Person(original);System.out.println("original: " + original.toString());System.out.println("copy: " + copy.toString());// 改变 拷贝对象的 引用类型字段的值copy.setAge(5);System.out.println("-------------改变copy 的基本类型 值后:-----------------");System.out.println("original: " + original.toString());System.out.println("copy: " + copy.toString());}

运行结果:说明基本类型浅拷贝,不是同一份

original: Person{name='John', age=30}
copy: Person{name='John', age=30}
-------------改变copy 的基本类型 值后:-----------------
original: Person{name='John', age=30}
copy: Person{name='John', age=5}
  • 通过构造函数 传递对象 实现浅拷贝 可变引用类型
class Person {private List<String> hobbies;private int age;// Constructorpublic Person(List<String> hobbies, int age) {this.hobbies = hobbies;this.age = age;}// Copy constructor for shallow copypublic Person(Person other) {this.hobbies = other.hobbies; // Reference copy for List (mutable)this.age = other.age;         // Value copy for int (primitive)}// Getters and Setterspublic List<String> getHobbies() {return hobbies;}public void setHobbies(List<String> hobbies) {this.hobbies = hobbies;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Person{hobbies=" + hobbies + ", age=" + age + "}";}public static void main(String[] args) {List<String> hobbies = new ArrayList<>();hobbies.add("Reading");hobbies.add("Swimming");Person original = new Person(hobbies, 30);Person copy = new Person(original);System.out.println("Original: " + original);System.out.println("Copy: " + copy);// Modify the hobbies list of the copycopy.getHobbies().add("Cycling");System.out.println("==============copy.getHobbies().add(\"Cycling\")之后: ==============");System.out.println("Original: " + original);System.out.println("Copy: " + copy);}
}
Original: Person{hobbies=[Reading, Swimming], age=30}
Copy: Person{hobbies=[Reading, Swimming], age=30}
==============copy.getHobbies().add("Cycling")之后: ==============
Original: Person{hobbies=[Reading, Swimming, Cycling], age=30}
Copy: Person{hobbies=[Reading, Swimming, Cycling], age=30}

分析:两个 对象的 List 类引用 始终指向同一个内存空间。copy 的操作list ,list 指向的空间的值发生了改变,两个仍然指向同一个内存空间,获取到的值一样

修改基本类型字段的值: 基本类型经浅拷贝,两个对象各有一份,基本类型字段所在内存空间不相同

public static void main(String[] args) {List<String> hobbies = new ArrayList<>();hobbies.add("Reading");hobbies.add("Swimming");Person original = new Person(hobbies, 30);Person copy = new Person(original);System.out.println("Original: " + original);System.out.println("Copy: " + copy);copy.setAge(5);System.out.println("==============copy.getHobbies().add(\"Cycling\")之后: ==============");System.out.println("Original: " + original);System.out.println("Copy: " + copy);}
Original: Person{hobbies=[Reading, Swimming], age=30}
Copy: Person{hobbies=[Reading, Swimming], age=30}
==============copy.getHobbies().add("Cycling")之后: ==============
Original: Person{hobbies=[Reading, Swimming], age=30}
Copy: Person{hobbies=[Reading, Swimming], age=5}
  • 通过 实现Cloneable接口,重写clone 方法,实现浅拷贝
package com.binbin.copy;
import java.util.ArrayList;
import java.util.List;
class Person implements  Cloneable{private List<String> hobbies;private int age;// Constructorpublic Person(List<String> hobbies, int age) {this.hobbies = hobbies;this.age = age;}// Copy constructor for shallow copypublic Person(Person other) {this.hobbies = other.hobbies; // Reference copy for List (mutable)this.age = other.age;         // Value copy for int (primitive)}// Getters and Setterspublic List<String> getHobbies() {return hobbies;}public void setHobbies(List<String> hobbies) {this.hobbies = hobbies;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Person{hobbies=" + hobbies + ", age=" + age + "}";}@Overridepublic Person clone() {try {Person clone = (Person) super.clone();// TODO: copy mutable state here, so the clone can't change the internals of the originalreturn clone;} catch (CloneNotSupportedException e) {throw new AssertionError();}}public static void main(String[] args) {List<String> hobbies = new ArrayList<>();hobbies.add("Reading");hobbies.add("Swimming");Person original = new Person(hobbies, 30);Person copy = new Person(original);System.out.println("Original: " + original);System.out.println("Copy: " + copy);copy.getHobbies().add("cycle");System.out.println("==============copy.getHobbies().add(\"Cycling\")之后: ==============");System.out.println("Original: " + original);System.out.println("Copy: " + copy);}
}

二、深拷贝

2.1 特点

  • 在 Java 中是指创建一个新对象,同时递归地复制所有引用类型的字段,这样使得新对象完全独立于原对象。新对象的引用类型字段指向新的的内存空间基本类型字段也是新的内存空间
  • 代码实现
import java.util.ArrayList;
import java.util.List;class Person  {private List<String> hobbies;private int age;// Constructorpublic Person(List<String> hobbies, int age) {this.hobbies = new ArrayList<>(hobbies); // Ensure independent copy for constructorthis.age = age;}// Deep copy methodpublic Person deepCopy() {List<String> copiedHobbies = new ArrayList<>(this.hobbies);return new Person(copiedHobbies, this.age);}// Getters and Setterspublic List<String> getHobbies() {return hobbies;}public void setHobbies(List<String> hobbies) {this.hobbies = hobbies;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Person{hobbies=" + hobbies + ", age=" + age + "}";}public static void main(String[] args) {List<String> hobbies = new ArrayList<>();hobbies.add("Reading");hobbies.add("Swimming");Person original = new Person(hobbies, 30);Person copy = original.deepCopy();System.out.println("Original: " + original);System.out.println("Copy: " + copy);// Modify the age of the copycopy.setAge(35);// Modify the hobbies list of the copycopy.getHobbies().add("Cycling");System.out.println("After modifications:");System.out.println("Original: " + original);System.out.println("Copy: " + copy);}
}
Original: Person{hobbies=[Reading, Swimming], age=30}
Copy: Person{hobbies=[Reading, Swimming], age=30}
After modifications:
Original: Person{hobbies=[Reading, Swimming], age=30}
Copy: Person{hobbies=[Reading, Swimming, Cycling], age=35}

分析:original 和 copy 的 hobbies 指向不同内存间,copy的hobbies 修改 不影响 original 的hobbies

三、总结

  • 深拷贝和浅拷贝的区别:深拷贝把给引用类型字段申请新的内存空间,并将原对象的数据复制到新的对象的空间中。浅拷贝只是引用赋值,还是指向同一内存空间
  • 浅拷贝还要考虑 可变引用类型字段 和 不可变引用类型字段
  • 浅拷贝可以实现Cloneable接口,重写clone 方法实现浅拷贝
  • 深拷贝的浅拷贝的基本类型字段拷贝时,都会创建新的空间

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

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

相关文章

docker搭建mongo分片集群

1、mongo分片集群 MongoDB分片集群是一种可扩展的数据库架构&#xff0c;用于处理大量数据和高并发访问。它将数据分成多个分片&#xff0c;并将这些分片分布在多个服务器上&#xff0c;从而实现数据的平衡存储和并行处理 。 通过使用MongoDB的分片集&#xff0c;可以实现数据…

NestJs 使用 RabbitMQ

NestJs 使用 RabbitMQ 既然是使用 RabbitMQ 那先不管其他的 把 RabbitMQ 装上再说 RabbitMQ 安装 这里直接找他们官网就行 Installing RabbitMQ | RabbitMQ 这里我们选择使用 docker 安装 快捷方便 这里直接参考&#xff1a; https://juejin.cn/post/719843080185010591…

鸿蒙面试心得

自疫情过后&#xff0c;java和web前端都进入了冰河时代。年龄、薪资、学历都成了找工作路上躲不开的门槛。 年龄太大pass 薪资要高了pass 学历大专pass 好多好多pass 找工作的路上明明阳关普照&#xff0c;却有一种凄凄惨惨戚戚说不清道不明的“优雅”意境。 如何破局&am…

宿主机无法通过ip连接wsl2解决方案

文章目录 原因排查网络模式win11防火墙关闭wsl ubuntu防火墙 如果之前能连接现在连接不上可以参考该方案 原因排查 网络模式win11防火墙(win11新增了Hyper-V防火墙)wsl2 ubuntu防火墙 网络模式 wsl2的默认网络模式是NAT&#xff0c;建议修改为镜像模式。在C:\Users\<User…

【深度学习】【Lora训练3】StabelDiffusion,Lora训练过程,秋叶包,Linux,SDXL Lora训练

为了便于使用&#xff0c;构建一个docker镜像来使用秋叶包。2024年6月26日。 docker run -it --gpus all -v /ssd/xiedong:/datax --net host kevinchina/deeplearning:pytorch2.3.0-cuda12.1-cudnn8-devel-xformers bashgit clone --recurse-submodules https://github.com/A…

408计算机网络--物理层

一、物理层概述 物理层是干嘛使得&#xff1f; 物理层解决如何在连接各种计算机的传输媒体上传输数据比特流&#xff0c;而不是指具体的传输媒体。 物理层主要任务是确定与传输媒体接口有关的一些特性。定义标准可以理解为插排上的两孔三孔 机械特性&#xff1a;定义物理连接…

Rill Data:实时数据分析的未来

欢迎来到 Rill Rill是从数据湖到仪表板的最快路径。 rilldata 与大多数 BI 工具不同&#xff0c;Rill 带有自己的嵌入式内存数据库。数据和计算位于同一位置&#xff0c;查询以毫秒为单位返回。 因此&#xff0c;您可以即时透视、切片和深入研究数据。 下载 Rill 开始建模数…

NFC使用

NFC&#xff08;Near Field Communication&#xff09;是一种短距离高频无线通信技术&#xff0c;允许电子设备之间进行非接触式点对点数据传输&#xff0c;交换数据。这项技术由非接触式射频识别&#xff08;RFID&#xff09;及互连互通技术整合演变而来&#xff0c;在单一芯片…

【论文解读】Performance Comparison of VVC, AV1, HEVC, and AVC for High Resolutions

论文下载地址:Performance Comparison of VVC, AV1, HEVC, and AVC for High Resolutions 时间:2024 年 作者:Miroslav Uhrina 摘要 研究背景:随着多媒体服务需求的增长,尤其是视频领域,企业和用户对视频的分辨率、帧率和采样精度的要求越来越高。这导致需要处理、存储和…

标签接口开发(富含完整CRUD开发流程)

文章目录 1.easyCode生成CRUD1.生成代码2.查看代码3.调整代码1.SubjectLabelDao.xml发现生成的select语句不带逗号&#xff01;&#xff01;&#xff01;1.解决方法&#xff1a;2.entity.java.vm3.dao.java.vm4.Mapper.xml.vm 2.重新生成代码3.SubjectLabelDao.java 删除Pageab…

【OceanBase诊断调优】—— 如何查找表被哪些其它表引用外键

本文详述如何查找指定表是否被其他表引用做外键。 适用版本 OceanBase 数据库所有版本。 MySQL 租户 obclient> select * from INFORMATION_SCHEMA.KEY_COLUMN_USAGE where REFERENCED_TABLE_NAME表名;Oracle 租户 obclient> SELECT TABLE_NAME FROM dba_constraint…

【RedHat】使用VMware Workstation创建配置RedHat操作系统

目录 &#x1f31e;1.前言 &#x1f31e;2. 使用 VMware Workstation 创建配置RedHat &#x1f33c;2.1 VMware Workstation 创建虚拟机 &#x1f33c;2.2 安装RedHat 7.6 &#x1f30a;2.2.1 添加光盘 &#x1f30a;2.2.2 开始安装操作系统 &#x1f30a;2.2.3 系统初始…

从基础到前沿:PLM产品生命周期管理系统在物料管理中的应用

在当今竞争激烈的市场中&#xff0c;制造型企业必须不断寻求提高效率和降低成本的方法。物料管理作为企业内部物流的核心环节&#xff0c;对于控制成本、提高生产效率、加快产品上市时间具有至关重要的作用。本文将探讨物料管理的重要性&#xff0c;以及如何通过三品产品生命周…

Python数据可视化-地图可视化

1.首先绘制实现数据可视化的思维导图 具体要实现什么功能-怎么处理&#xff0c;先把思路写好 数据来源&#xff1a; 爬取的数据 运行结果&#xff1a; 部分代码&#xff1a; 完整代码请在下方↓↓↓&#x1f447;获取 转载请注明出处&#xff01;

75101A 1553B总线测试模块

75101A 1553B总线测试模块 75101A 1553B总线测试模块是单通道多功能&#xff0c;符合CPCI/PXI总线的标准3U尺寸模块&#xff0c;可同时用作BC、RTs和BM&#xff0c;其中BM具有比特误码、highbit、lowbit、highword、lowword、校验错误、消息错误检测以及最大256M字节的数据捕…

新能源革命风起云涌:创新科技引领可持续发展新篇章

随着全球气候变化和环境问题日益严峻&#xff0c;新能源革命正以其不可阻挡的势头&#xff0c;席卷着世界的每一个角落。 创新科技在这场革命中发挥着至关重要的作用&#xff0c;它不仅是新能源开发利用的引擎&#xff0c;更是推动可持续发展的关键力量。 新能源革命的核心在于…

ubuntu如何切换到root用户

1、主要指令&#xff1a; sudo -i su root 2、示例 3、其他说明 在Ubuntu&#xff08;以及大多数其他基于Linux的操作系统中&#xff09;&#xff0c;切换到root用户通常意味着获得了对系统的完全访问权限。这种权限允许执行以下操作&#xff08;但不限于这些&#xff09;…

非递归创建二叉查找树

非递归创建二叉查找树代码。 #include <stdio.h> #include <stdlib.h>typedef int KeyType; typedef struct BSTNode{KeyType key;struct BSTNode *lchild,*rchild; }BSTNode,*BiTree;//王道书上的递归写法&#xff0c;代码简单&#xff0c;但是理解有难度 //int …

Spring AI 实现调用openAi 多模态大模型

什么是多模态? 多模态(Multimodal)指的是数据或信息的多种表现形式。在人工智能领域,我们经常会听到这个词,尤其是在近期大型模型(如GPT-4)开始支持多模态之后。 模态:模态是指数据的一种形式,例如文本、图像、音频等。每一种形式都是一种模态。多模态:多模态就是将…

如何选择智能语音机器人系统?ai电销机器人部署源码二开

智能语音机器人已经成熟运用到各个行业了&#xff0c;如房地产行业、教育培训招生行业、电商店铺行业、快递物流通知等等。为什么要用智能语音机器人代替人工呢&#xff0c;智能语音机器人系统如何选择呢&#xff1f; 为什么要用智能语音机器人代替人工&#xff1f; 1、用人成本…