Java:对象的浅拷贝与深拷贝

目录

一、概念

二、实现方式

2.1 浅拷贝(不推荐)

2.2 深拷贝

2.2.1 方法一:重写 clone() 方法并递归克隆(常用)

2.2.2 方法二:通过序列化实现(更强大,但更重)

2.2.3 使用拷贝构造方法或拷贝工厂(推荐)


一、概念

浅拷贝 (Shallow Copy):只复制对象本身以及对象中的基本数据类型字段的值,而对于对象中的引用类型字段,则只复制其内存地址(即引用),而不复制引用的对象本身。

影响:原始对象和拷贝对象中的引用字段指向的是同一个堆内存中的子对象。修改其中一个对象的引用字段的内容,另一个对象的对应字段也会“看到”这个变化。

深拷贝 (Deep Copy):仅复制对象本身和基本数据类型字段的值,还会递归地复制所有引用类型字段所指向的对象,直到所有可达的对象都被复制。

影响:原始对象和拷贝对象完全独立,它们所有的引用字段都指向不同的对象。修改其中一个对象的任何内容,都不会影响另一个对象。

二、实现方式

2.1 浅拷贝(不推荐)

实现方式:依靠Object 类的 clone() 方法。

实现条件:

  • 被拷贝的类实现 Cloneable 接口(这是一个标记接口,没有方法)。

  • 被拷贝的类重写 Object 的 clone() 方法,并在其中调用 super.clone()

public class Person implements Cloneable {private String name;        // String (不可变对象,可视为基本类型)private int age;            // 基本类型private Address address;    // 引用类型// 构造方法、getters、setters 省略...@Overridepublic Object clone() throws CloneNotSupportedException {// 直接调用Object的clone()方法,完成基本数据类型和引用地址的复制return super.clone();}
}public class Address {private String city;private String street;// 构造方法、getters、setters...
}public class TestShallowCopy {public static void main(String[] args) throws CloneNotSupportedException {Address addr = new Address("北京", "长安街");Person original = new Person("张三", 25, addr);// 进行浅拷贝Person copied = (Person) original.clone();System.out.println(original == copied);       // false,是两个不同的对象System.out.println(original.getName() == copied.getName()); // true,String池或同一对象(可能)System.out.println(original.getAddress() == copied.getAddress()); // true!关键在这里:引用指向同一个Address对象// 修改拷贝对象的引用类型成员copied.getAddress().setCity("上海");// 原始对象的address也被修改了!System.out.println(original.getAddress().getCity()); // 输出:上海}
}

2.2 深拷贝

2.2.1 方法一:重写 clone() 方法并递归克隆(常用)

// 1、让 Address 类也变得可克隆(实现 Cloneable 并重写 clone())
public class Address implements Cloneable {private String city;private String street;// ... 其他代码 ...@Overridepublic Object clone() throws CloneNotSupportedException {return super.clone();}
}// 2、在 Person 的 clone() 方法中,不仅调用 super.clone(),还要手动克隆 address 字段
public class Person implements Cloneable {private String name;private int age;private Address address;// ... 其他代码 ...@Overridepublic Object clone() throws CloneNotSupportedException {// 1. 先调用super.clone()完成浅拷贝Person copied = (Person) super.clone();// 2. 对引用类型字段,手动调用其clone()方法进行深拷贝copied.address = (Address) this.address.clone();// 3. 返回深拷贝后的对象return copied;}
}// 3、测试
public class TestDeepCopy {public static void main(String[] args) throws CloneNotSupportedException {Address addr = new Address("北京", "长安街");Person original = new Person("张三", 25, addr);Person copied = (Person) original.clone();System.out.println(original.getAddress() == copied.getAddress()); // false!现在是不同的Address对象// 修改拷贝对象的addresscopied.getAddress().setCity("上海");// 原始对象的address不受影响System.out.println(original.getAddress().getCity()); // 输出:北京System.out.println(copied.getAddress().getCity());   // 输出:上海}
}

2.2.2 方法二:通过序列化实现(更强大,但更重)

前提:所有涉及到的类都必须实现 java.io.Serializable 接口。

import java.io.*;public class DeepCopyUtil {@SuppressWarnings("unchecked")public static <T extends Serializable> T deepCopy(T object) {try (ByteArrayOutputStream baos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(baos)) {// 将对象写入字节流oos.writeObject(object);oos.flush();try (ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());ObjectInputStream ois = new ObjectInputStream(bais)) {// 从字节流中读出新的对象return (T) ois.readObject();}} catch (IOException | ClassNotFoundException e) {throw new RuntimeException("Deep copy failed", e);}}
}// Person和Address类都需要实现Serializable接口
public class Person implements Serializable { ... }
public class Address implements Serializable { ... }// 使用工具类进行深拷贝
Person original = new Person(...);
Person copied = DeepCopyUtil.deepCopy(original); // 完美的深拷贝

优点:无需关心对象内部复杂的引用结构,序列化机制会自动完成所有递归复制。
缺点:性能开销比 clone() 方法大;所有相关类都必须实现 Serializable 接口。

2.2.3 使用拷贝构造方法或拷贝工厂(推荐)

这是一种非常推荐的方式,它不依赖 Cloneable 接口,代码更清晰,也更灵活。

  • 拷贝构造方法:接受一个同一类型的参数,并据此构造一个新对象。

  • 拷贝工厂:一个静态方法,用于完成拷贝。

public class Person {private String name;private int age;private Address address;// 拷贝构造方法public Person(Person other) {this.name = other.name;this.age = other.age;// 对引用类型,调用其拷贝构造方法进行深拷贝this.address = new Address(other.address); // 假设Address也有拷贝构造方法}// 拷贝工厂 (静态方法)public static Person newInstance(Person other) {return new Person(other);}
}public class Address {private String city;private String street;// Address的拷贝构造方法public Address(Address other) {this.city = other.city;this.street = other.street;}
}// 使用
Person original = new Person(...);
Person copied = new Person(original); // 使用拷贝构造方法
// 或
Person copied2 = Person.newInstance(original); // 使用拷贝工厂

优点:代码意图明确,易于控制和扩展,是《Effective Java》推荐的方式。

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

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

相关文章

佰钧成 社招 一面

1. “评估需求、排期”的工作流程&#xff1f; “我的工作流程一般是这样的&#xff1a; 需求评审&#xff1a; 首先会和产品、后端同学一起过需求&#xff0c;确保我完全理解了业务背景和要实现的价值&#xff0c;而不仅仅是功能点。技术方案设计&#xff1a; 之后&#xff0c…

最短路径问题(图论)

1 Floyd 作用&#xff1a; 求图中所有顶点之间的最短路径&#xff0c;包括有向图或者无向图&#xff0c;权重正负皆可&#xff0c;用来一次性求所有点之间的最短路径。 思路是 通过逐步扩大中间层&#xff0c;使得最短路径不断被更新&#xff0c;直到中间层扩大到n位置&#…

2025年8月新算法—云漂移优化算法(Cloud Drift Optimization Algorithm, CDO)

1、简介 这项研究介绍了云漂移优化&#xff08;数位长&#xff09;算法&#xff0c;这是一种创新的自然启发的元启发式方法来解决复杂的优化问题。CDO模仿受大气力影响的云粒子的动态行为&#xff0c;在探索和利用之间取得了微妙的平衡。它具有自适应权重调整机制&#xff0c;可…

VS Code进行.NET开发时使用断点和热重载

VS Code 调试热重载 1. VS Code 设置 安装扩展&#xff1a;C#、C# Dev Kit设置中搜索hot reload&#xff0c;选择C#开发工具包&#xff0c;把下图的几项全部打勾2. 启动项目&#xff08;仅用左侧“运行和调试”&#xff09; 打开解决方案&#xff0c;选你的启动项目的“.NET La…

mysqlbinlog解析命令

解析 MySQL Binlog 详细信息的命令以下是解析 MySQL Binlog 详细信息的常用命令&#xff1a;1. 基本 binlog 解析命令# 查看 binlog 文件内容&#xff08;基本格式&#xff09; mysqlbinlog /var/lib/mysql/mysql-bin.000001# 查看特定时间段的 binlog mysqlbinlog --start-dat…

算法训练营day60 图论⑩ Bellman_ford 队列优化算法、判断负权回路、单源有限最短路(修改后版本)

增加对最短路径的优化算法、负权回路、单源有限最短的讲解 Bellman_ford 队列优化算法 -------------------------------------------------------------------------------- 8.24更新&#xff1a;该算法是针对带负值的最短路径的优化算法&#xff0c;核心通过队列来实现&…

Python 学习(十六) 下一代 Python 包管理工具:UV

目录1. UV 介绍1.1 什么是UV&#xff1f;1.2 UV的核心优势1.3 UV和其他工具对比1&#xff09;UV vs. pipvirtualenv2&#xff09;UV vs. Conda3&#xff09;UV vs. Poetry4&#xff09;功能对比表2. UV的安装与常用命令2.1 安装UV1&#xff09;使用官方安装脚本&#xff08;推荐…

Redis学习笔记 ----- 缓存

一、什么是缓存 缓存&#xff08;Cache&#xff09;是数据交换的缓冲区&#xff0c;是存储数据的临时地方&#xff0c;一般读写性能较高。 &#xff08;一&#xff09;缓存的作用 降低后端负载&#xff1a;减少对数据库等后端存储的直接访问压力。提高读写效率&#xff0c;降低…

React响应式链路

文章目录响应式链路的核心环节1.状态定义与初始化2.状态更新触发&#xff08;状态变更&#xff09;3.调度更新&#xff08;Scheduler&#xff09;4.重新渲染&#xff08;Render 阶段&#xff09;5.协调&#xff08;Reconciliation&#xff09;与 Fiber 架构6.提交更新&#xff…

软件设计师——计算机网络学习笔记

一、计算机网络 网络基础 1. 计算机网络的分类2. 网络拓扑结构 总线型(利用率低、干扰大、价格低) 星型(交换机形成的局域网、中央单元负荷大) 环型(流动方向固定、效率低扩充难) 树型(总线型的扩充、分级结构) 分布式(任意节点连接、管理难成本高)一般来说&#xff0c;办公室局…

1200 SCL学习笔记

一. IF. 如果。下面是一个起保停IF #I_start AND NOT #I_stop THEN //如果I_start接通 和 I_stop没有接通#Q_run : 1; //输出Q_run 接通 ELSIF #I_stop THEN //如果I_stop接通#Q_run : 0; //。。。。。。 END_IF;二. CASECASE…

单例模式与线程池

1. 单例模式单例模式是一种常用的设计模式&#xff0c;它确保一个类只有一个实例&#xff0c;并提供一个全局访问点来获取这个实例。这种模式在需要控制资源访问、管理共享状态或协调系统行为时非常有用。单例模式的核心特点&#xff1a;私有构造函数&#xff1a;防止外部通过n…

Chrome和Edge如何开启暗黑模式

Edge和Chrome浏览器都提供了实验性功能&#xff0c;可以通过修改实验性设置来开启暗黑模式。 在浏览器地址栏中输入edge://flags/&#xff08;Edge&#xff09;或chrome://flags/&#xff08;Chrome&#xff09;。在搜索框中输入“dark”&#xff0c;找到与暗黑模式相关的选项。…

【科研绘图系列】浮游植物的溶解性有机碳与初级生产力的关系

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍 数据准备 数据处理 溶解性有机碳(DOC)与初级生产力(NPP)的关系 溶解性有机碳(DOC)与光照强度(PAR)的关系 数据可视化 加载R包 数据下载 导入数据 画图1 画图2 总结 系统信…

IDEA相关的设置和技巧

IDEA相关的设置和技巧 我的博客对应文章地址 1.布局设置 IDEA的布局自定义程度很高&#xff0c;顶部工具栏&#xff0c;侧边栏都可以随意定制&#xff0c;设置好的布局方案可以保存&#xff0c;在新项目中快速使用 1.1 工具栏设置 [!tip] 举个例子&#xff1a;比如我要在顶部…

AWS Lambda 完全指南:解锁无服务器架构的强大力量

在云计算的发展浪潮中,无服务器(Serverless) 架构已然成为构建现代应用的新范式。而在这场变革的中心,AWS Lambda 作为开创性的 Function-as-a-Service (FaaS) 服务,彻底改变了我们部署和运行代码的方式。 本文将带您深入探索 AWS Lambda,从核心概念、工作原理到高级实践…

人工智能时代下普遍基本收入(UBI)试验的实践与探索——以美国硅谷试点为例

一、硅谷UBI试验的最新进展&#xff08;2025年&#xff09;1. 试验规模与资金来源圣克拉拉县试点&#xff1a;硅谷所在地圣克拉拉县针对脱离寄养家庭的年轻人开展UBI试验&#xff0c;每月发放1000美元补贴&#xff0c;持续1-2年&#xff0c;覆盖约60名参与者&#xff0c;成本约…

云计算之云主机Linux是什么?有何配置?如何选?

一、云环境如何选择Linux发行版 1.1、Linux在各个领域的发展 Linux在各个领域的发展序号Linux发展领域说明1Linux在服务器领域的发展目前Linux在服务器领域已经占据95%的市场份额&#xff0c;同时Linux在服务器市场的迅速崛起&#xff0c;已经引起全球IT产业的高度关注&#xf…

XCVU13P-2FHGB2104E Xilinx(AMD)Virtex UltraScale+ FPGA

XCVU13P-2FHGB2104E 是 Xilinx&#xff08;AMD&#xff09;Virtex UltraScale FPGA 系列中的一款高性能芯片&#xff0c;适用于需要大量逻辑资源、高带宽和高速数据传输的应用场景。作为该系列中的旗舰产品&#xff0c;XCVU13P-2FHGB2104I 结合了强大的处理能力和灵活的可编程性…

自动化单词例句获取系统设计方案

方案一 (网络爬虫) 这个方案的核心思路是:创建一个自动化的脚本,该脚本会读取你 MongoDB 中的单词,然后去一个免费的在线词典网站上抓取这些单词的例句,最后将抓取到的例句存回你的 MongoDB 数据库中对应的单词条目下。 一、 核心思路与技术选型 自动化脚本: 我们将使用 P…