当前位置: 首页 > news >正文

java 深拷贝 浅拷贝 详解

在 Java 中,深拷贝浅拷贝是对象拷贝(复制)时的两个重要概念,它们决定了拷贝后的对象与原对象之间的关联性。以下是深拷贝和浅拷贝的详解,包括定义、实现方式及其区别。


1. 概念解释

1.1 浅拷贝(Shallow Copy)

浅拷贝是对对象的一种表层复制

  • 基本数据类型的字段会复制其值。
  • 引用数据类型的字段会复制其引用地址(即引用同一个对象)。

拷贝后的对象与原对象共享引用类型的成员。

特性

  • 拷贝对象与原对象的引用类型字段指向同一个内存地址。
  • 修改引用类型的内容会影响到原对象。

1.2 深拷贝(Deep Copy)

深拷贝是对对象的一种完全复制

  • 基本数据类型的字段会复制其值。
  • 引用数据类型的字段会递归拷贝新对象,即创建新的内存空间,拷贝后不共享引用。

拷贝后的对象与原对象完全独立。

特性

  • 拷贝对象与原对象互不影响,任何修改只会影响对应对象。

2. 示例代码

2.1 浅拷贝示例

使用 Object.clone() 方法实现浅拷贝:

class Person implements Cloneable {String name;Address address;Person(String name, Address address) {this.name = name;this.address = address;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone(); // 调用 Object 的 clone 方法}
}class Address {String city;Address(String city) {this.city = city;}
}public class ShallowCopyExample {public static void main(String[] args) throws CloneNotSupportedException {Address address = new Address("New York");Person person1 = new Person("John", address);// 浅拷贝Person person2 = (Person) person1.clone();// 修改拷贝对象的引用类型字段person2.address.city = "Los Angeles";// 原对象的引用类型字段也被修改System.out.println(person1.address.city); // 输出:Los Angeles}
}

2.2 深拷贝示例

手动实现深拷贝:

class Person implements Cloneable {String name;Address address;Person(String name, Address address) {this.name = name;this.address = address;}@Overrideprotected Object clone() throws CloneNotSupportedException {// 创建一个浅拷贝Person clonedPerson = (Person) super.clone();// 手动深拷贝引用类型字段clonedPerson.address = new Address(this.address.city);return clonedPerson;}
}class Address {String city;Address(String city) {this.city = city;}
}public class DeepCopyExample {public static void main(String[] args) throws CloneNotSupportedException {Address address = new Address("New York");Person person1 = new Person("John", address);// 深拷贝Person person2 = (Person) person1.clone();// 修改拷贝对象的引用类型字段person2.address.city = "Los Angeles";// 原对象的引用类型字段未被修改System.out.println(person1.address.city); // 输出:New York}
}

3. 区别对比

特性浅拷贝深拷贝
拷贝方式仅复制对象的基本类型字段和引用类型字段的引用地址。复制对象的所有字段,包括引用类型字段所指向的对象。
内存分配原对象和拷贝对象共享引用类型字段的内存地址。原对象和拷贝对象完全独立,占用不同的内存空间。
修改影响修改拷贝对象的引用类型字段会影响原对象。修改拷贝对象不会影响原对象。
实现复杂度简单,可以直接使用 Object.clone() 方法。较复杂,需要手动实现递归拷贝。
适用场景引用类型字段无需独立,或对性能要求高的场景。引用类型字段需要独立且完全隔离的场景。

4. 实现深拷贝的常用方式

4.1 使用 clone() 方法

  • 递归实现拷贝每个引用类型字段。
  • 需要确保所有类都实现 Cloneable 接口,并重写 clone() 方法。

4.2 使用序列化

通过将对象序列化为字节流再反序列化来实现深拷贝:

import java.io.*;class Person implements Serializable {String name;Address address;Person(String name, Address address) {this.name = name;this.address = address;}
}class Address implements Serializable {String city;Address(String city) {this.city = city;}
}public class DeepCopyWithSerialization {public static void main(String[] args) throws IOException, ClassNotFoundException {Address address = new Address("New York");Person person1 = new Person("John", address);// 深拷贝Person person2 = deepCopy(person1);// 修改拷贝对象的引用类型字段person2.address.city = "Los Angeles";// 原对象的引用类型字段未被修改System.out.println(person1.address.city); // 输出:New York}// 序列化深拷贝方法private static <T> T deepCopy(T object) throws IOException, ClassNotFoundException {ByteArrayOutputStream byteOut = new ByteArrayOutputStream();ObjectOutputStream out = new ObjectOutputStream(byteOut);out.writeObject(object);ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());ObjectInputStream in = new ObjectInputStream(byteIn);return (T) in.readObject();}
}

4.3 使用第三方库

一些第三方库(如 Apache Commons Lang 的 SerializationUtils)可以简化深拷贝的实现。


5. 注意事项

  1. Cloneable 接口的限制

    • 默认的 Object.clone() 方法只能实现浅拷贝,需要手动实现深拷贝。
  2. 性能考虑

    • 深拷贝通常比浅拷贝耗时更多,尤其是引用类型字段复杂时。
  3. 引用循环问题

    • 如果对象内部存在循环引用(即对象引用自身或其他对象),需要特别处理,避免递归拷贝时发生栈溢出。
  4. 使用场景选择

    • 如果引用类型字段无需独立修改,浅拷贝通常已足够。
    • 如果引用类型字段需要独立,且修改后不影响原对象,使用深拷贝。

6. 总结

浅拷贝深拷贝
仅复制值类型字段和引用地址复制值类型字段,并递归复制引用类型字段所指向的对象
性能较高,但存在引用共享的问题性能较低,但保证拷贝对象独立
适用于引用类型字段无需独立修改的场景适用于引用类型字段需要独立且完全隔离的场景

在实际应用中,应根据具体需求选择合适的拷贝方式。浅拷贝适用于简单的场景,而深拷贝更适合复杂对象需要完全隔离的场景。

相关文章:

java 深拷贝 浅拷贝 详解

在 Java 中&#xff0c;深拷贝和浅拷贝是对象拷贝&#xff08;复制&#xff09;时的两个重要概念&#xff0c;它们决定了拷贝后的对象与原对象之间的关联性。以下是深拷贝和浅拷贝的详解&#xff0c;包括定义、实现方式及其区别。 1. 概念解释 1.1 浅拷贝&#xff08;Shallow …...

针对git、giteeVSCode连接的使用 || Live Share插件使用

1.下载git 链接 打开终端&#xff0c;桌面鼠标右键 2.配置密钥 登录gitee。 设置密钥 查看官方文档 跟着教程 复制最后的输出进行密钥添加 验证是否添加成功 3.创建&连接远程仓库 创建仓库 git终端进行配置 远程仓库克隆到本地 桌面终端clone,克隆他人|自己的仓库到本地…...

如何解决Ubuntu 20.04中Vim编辑器在按下Ctrl+S时暂停响应的问题

如何解决Ubuntu 20.04中Vim编辑器在按下CtrlS时暂停响应的问题 在Ubuntu 20.04中使用Vim编辑器时&#xff0c;用户可能会遇到按下CtrlS后编辑器似乎“卡死”或无响应的情况。这个问题实际上源于历史悠久的终端行为&#xff0c;而非Vim本身或操作系统的缺陷。以下是详细的分析及…...

mybatisPlus打印sql配置

MyBatis-Plus 提供了方便的配置方式来打印 SQL 查询语句&#xff0c;以便进行调试和性能分析。可以通过配置 log 来输出 SQL 语句以及执行的参数。 方法 1&#xff1a;通过 application.properties 或 application.yml 配置打印 SQL 可以通过配置 application.properties 或 a…...

Redis 内存管理

参考&#xff1a;面试官&#xff1a;为什么 Redis 不立刻删除已经过期的数据&#xff1f; 目录 1.Redis 给缓存数据设置过期时间有什么用&#xff1f; 2.Redis 是如何判断数据是否过期的呢&#xff1f; 3.Redis 过期 key 删除策略了解么&#xff1f; 4.大量 key 集中过期怎…...

Excel表文本函数、日期和时间函数

一、文本函数 函数说明CHAR返回字符代码所对应的字符CLEAN删除文本中的所有不可打印字符CODE返回文本字符串首字符的代码CONCATENATE合并多个文本字符串EXACT检查两个文本是否完全相同FIND查找文本中某个字符串的位置LEFT从文本的左边开始返回指定数量的字符LEN返回文本字符串…...

从零到一:利用 AI 开发 iOS App 《震感》的编程之旅

在网上看到一篇关于使用AI开发的编程经历&#xff0c;分享给大家 作者是如何在没有 iOS 开发经验的情况下&#xff0c;借助 AI&#xff08;如 Claude 3 模型&#xff09;成功开发并发布《震感》iOS 应用。 正文开始 2022 年 11 月&#xff0c;ChatGPT 诞生并迅速引发全球关注。…...

基于Java Springboot幼儿园管理系统

一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术&#xff1a;Html、Css、Js、Vue、Element-ui 数据库&#xff1a;MySQL 后端技术&#xff1a;Java、Spring Boot、MyBatis 三、运行环境 开发工具&#xff1a;IDEA/eclipse 数据…...

Python小白学习教程从入门到入坑------习题课2(基础巩固)

目录 一、选择题 二、实战题 2.1 实战1&#xff1a;输入一个年份&#xff0c;判断是否是闰年 2.2 实战2&#xff1a;模拟10086查询功能 2.3 实战3&#xff1a;使用嵌套循环输出九九乘法表 2.4 实战4&#xff1a;猜数游戏 一、选择题 1、以下选项符合Python语法要求且能够…...

基于IPMI_SSH的服务器硬件监控指标解读

随着企业IT架构的日益复杂化&#xff0c;对服务器的实时监控和管理变得至关重要。监控易作为一款功能强大的监控软件&#xff0c;支持通过IPMI_SSH的方式对服务器硬件进行远程监控&#xff0c;确保服务器的稳定运行。本文将针对监控易中基于IPMI_SSH的服务器硬件监控指标进行解…...

数据结构-二叉树及其遍历

🚀欢迎来到我的【数据结构】专栏🚀 🙋我是小蜗,一名在职牛马。🐒我的博客主页​​​​​​ ➡️ ➡️ 小蜗向前冲的主页🙏🙏欢迎大家的关注,你们的关注是我创作的最大动力🙏🙏🌍前言 本篇文章咱们聊聊数据结构中的树,准确的说因该是只说一说二叉树以及相…...

(33)iptables设置防火墙策略常用命令(docker环境、非docker环境)

#普通环境&#xff08;非docker&#xff09; # 拒绝所有对端口 31001 的访问 iptables -A INPUT -p tcp --dport 31001 -j DROP # 允许 IP 地址 20.59.30.77 访问端口 31001 (此处用的是虚拟机 所以要使用nat地址的网关) iptables -I INPUT 1 -p tcp -s 20.59.30.77 --dpor…...

fastadmin中动态下拉组件(SelectPage)的使用

实现的功能如下&#xff1a; 1、支持模糊搜索&#xff1b;2、分页功能&#xff1b;3支持多选 官方文档&#xff1a;https://doc.fastadmin.net/doc/178.html html页面引用组件 <div class"form-group"><label class"control-label col-xs-12 col-sm-2…...

通过Python 调整Excel行高、列宽

在Excel中&#xff0c;默认的行高和列宽可能不足以完全显示某些单元格中的内容&#xff0c;特别是当内容较长时。通过调整行高和列宽&#xff0c;可以确保所有数据都能完整显示&#xff0c;避免内容被截断。合理的行高和列宽可以使表格看起来更加整洁和专业&#xff0c;尤其是在…...

力扣-Mysql-3278. 寻找数据科学家职位的候选人 II(中等)

一、题目来源 3278. 寻找数据科学家职位的候选人 II - 力扣&#xff08;LeetCode&#xff09; 二、数据表结构 表&#xff1a;Candidates ----------------------- | Column Name | Type | ----------------------- | candidate_id | int | | skill | varch…...

Android笔记(三十六):封装一个Matrix从顶部/底部对齐的ImageView

背景 ImageView的scaleType默认显示图片是这样&#xff0c;但是有时候设计稿需求希望图片左右能紧贴着ImageView左右边缘&#xff0c;又不破坏图片的比例&#xff0c;用自带的matrix&#xff0c;centerCrop等都可以满足 但是都会造成图片的某些区域被裁剪了&#xff0c;如果设…...

web 入门

学习 Web 开发的基础&#xff0c;建议从以下几个方面入门&#xff0c;按步骤循序渐进学习核心知识&#xff1a; 1. 了解 Web 的基础概念 在开始编码之前&#xff0c;先理解 Web 开发的基本工作原理&#xff1a; Web 前端与后端&#xff1a; 前端&#xff1a;负责用户界面和用…...

京东 2025届秋招 自然语言处理

文章目录 个人情况一面/HR面 10min二面/技术面 1h三面/技术面 1h四面/线下HR面 20min 个人情况 先说一下个人情况&#xff1a; 学校情况&#xff1a;211本中9硕&#xff0c;本硕学校都一般&#xff0c;本硕都是计算机科班&#xff0c;但研究方向并不是NLP&#xff0c;而是图表…...

Mybatis框架之模板方法模式 (Template Method Pattern)

MyBatis 中也使用到了 模板方法模式 (Template Method Pattern)&#xff0c;主要体现在 执行 SQL 语句的流程控制 上。模板方法模式允许 MyBatis 定义数据库操作的标准流程&#xff0c;并允许子类或特定实现类去实现某些步骤。这种模式使得 MyBatis 能够在处理不同类型的 SQL 操…...

【进阶系列】python简单爬虫实例

python有一个很强大的功能就是爬取网页的信息&#xff0c;这里是CNBlogs 网站&#xff0c;我们将以此网站为实例&#xff0c;爬取指定个页面的大标题内容。代码如下&#xff1a; 首先是导入库&#xff1a; # 导入所需的库 import requests # 用于发送HTTP请求 from bs4 impor…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)

文章目录 1.什么是Redis&#xff1f;2.为什么要使用redis作为mysql的缓存&#xff1f;3.什么是缓存雪崩、缓存穿透、缓存击穿&#xff1f;3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

解锁数据库简洁之道:FastAPI与SQLModel实战指南

在构建现代Web应用程序时&#xff0c;与数据库的交互无疑是核心环节。虽然传统的数据库操作方式&#xff08;如直接编写SQL语句与psycopg2交互&#xff09;赋予了我们精细的控制权&#xff0c;但在面对日益复杂的业务逻辑和快速迭代的需求时&#xff0c;这种方式的开发效率和可…...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

(二)原型模式

原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1

每日一言 生活的美好&#xff0c;总是藏在那些你咬牙坚持的日子里。 硬件&#xff1a;OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写&#xff0c;"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

【单片机期末】单片机系统设计

主要内容&#xff1a;系统状态机&#xff0c;系统时基&#xff0c;系统需求分析&#xff0c;系统构建&#xff0c;系统状态流图 一、题目要求 二、绘制系统状态流图 题目&#xff1a;根据上述描述绘制系统状态流图&#xff0c;注明状态转移条件及方向。 三、利用定时器产生时…...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

&#x1f50d; 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术&#xff0c;可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势&#xff0c;还能有效评价重大生态工程…...

初探Service服务发现机制

1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能&#xff1a;服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源&#xf…...

【笔记】WSL 中 Rust 安装与测试完整记录

#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统&#xff1a;Ubuntu 24.04 LTS (WSL2)架构&#xff1a;x86_64 (GNU/Linux)Rust 版本&#xff1a;rustc 1.87.0 (2025-05-09)Cargo 版本&#xff1a;cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...