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. 注意事项
-
Cloneable
接口的限制:- 默认的
Object.clone()
方法只能实现浅拷贝,需要手动实现深拷贝。
- 默认的
-
性能考虑:
- 深拷贝通常比浅拷贝耗时更多,尤其是引用类型字段复杂时。
-
引用循环问题:
- 如果对象内部存在循环引用(即对象引用自身或其他对象),需要特别处理,避免递归拷贝时发生栈溢出。
-
使用场景选择:
- 如果引用类型字段无需独立修改,浅拷贝通常已足够。
- 如果引用类型字段需要独立,且修改后不影响原对象,使用深拷贝。
6. 总结
浅拷贝 | 深拷贝 |
---|---|
仅复制值类型字段和引用地址 | 复制值类型字段,并递归复制引用类型字段所指向的对象 |
性能较高,但存在引用共享的问题 | 性能较低,但保证拷贝对象独立 |
适用于引用类型字段无需独立修改的场景 | 适用于引用类型字段需要独立且完全隔离的场景 |
在实际应用中,应根据具体需求选择合适的拷贝方式。浅拷贝适用于简单的场景,而深拷贝更适合复杂对象需要完全隔离的场景。
相关文章:
java 深拷贝 浅拷贝 详解
在 Java 中,深拷贝和浅拷贝是对象拷贝(复制)时的两个重要概念,它们决定了拷贝后的对象与原对象之间的关联性。以下是深拷贝和浅拷贝的详解,包括定义、实现方式及其区别。 1. 概念解释 1.1 浅拷贝(Shallow …...

针对git、giteeVSCode连接的使用 || Live Share插件使用
1.下载git 链接 打开终端,桌面鼠标右键 2.配置密钥 登录gitee。 设置密钥 查看官方文档 跟着教程 复制最后的输出进行密钥添加 验证是否添加成功 3.创建&连接远程仓库 创建仓库 git终端进行配置 远程仓库克隆到本地 桌面终端clone,克隆他人|自己的仓库到本地…...
如何解决Ubuntu 20.04中Vim编辑器在按下Ctrl+S时暂停响应的问题
如何解决Ubuntu 20.04中Vim编辑器在按下CtrlS时暂停响应的问题 在Ubuntu 20.04中使用Vim编辑器时,用户可能会遇到按下CtrlS后编辑器似乎“卡死”或无响应的情况。这个问题实际上源于历史悠久的终端行为,而非Vim本身或操作系统的缺陷。以下是详细的分析及…...
mybatisPlus打印sql配置
MyBatis-Plus 提供了方便的配置方式来打印 SQL 查询语句,以便进行调试和性能分析。可以通过配置 log 来输出 SQL 语句以及执行的参数。 方法 1:通过 application.properties 或 application.yml 配置打印 SQL 可以通过配置 application.properties 或 a…...

Redis 内存管理
参考:面试官:为什么 Redis 不立刻删除已经过期的数据? 目录 1.Redis 给缓存数据设置过期时间有什么用? 2.Redis 是如何判断数据是否过期的呢? 3.Redis 过期 key 删除策略了解么? 4.大量 key 集中过期怎…...
Excel表文本函数、日期和时间函数
一、文本函数 函数说明CHAR返回字符代码所对应的字符CLEAN删除文本中的所有不可打印字符CODE返回文本字符串首字符的代码CONCATENATE合并多个文本字符串EXACT检查两个文本是否完全相同FIND查找文本中某个字符串的位置LEFT从文本的左边开始返回指定数量的字符LEN返回文本字符串…...

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

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

Python小白学习教程从入门到入坑------习题课2(基础巩固)
目录 一、选择题 二、实战题 2.1 实战1:输入一个年份,判断是否是闰年 2.2 实战2:模拟10086查询功能 2.3 实战3:使用嵌套循环输出九九乘法表 2.4 实战4:猜数游戏 一、选择题 1、以下选项符合Python语法要求且能够…...
基于IPMI_SSH的服务器硬件监控指标解读
随着企业IT架构的日益复杂化,对服务器的实时监控和管理变得至关重要。监控易作为一款功能强大的监控软件,支持通过IPMI_SSH的方式对服务器硬件进行远程监控,确保服务器的稳定运行。本文将针对监控易中基于IPMI_SSH的服务器硬件监控指标进行解…...

数据结构-二叉树及其遍历
🚀欢迎来到我的【数据结构】专栏🚀 🙋我是小蜗,一名在职牛马。🐒我的博客主页 ➡️ ➡️ 小蜗向前冲的主页🙏🙏欢迎大家的关注,你们的关注是我创作的最大动力🙏🙏🌍前言 本篇文章咱们聊聊数据结构中的树,准确的说因该是只说一说二叉树以及相…...
(33)iptables设置防火墙策略常用命令(docker环境、非docker环境)
#普通环境(非docker) # 拒绝所有对端口 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)的使用
实现的功能如下: 1、支持模糊搜索;2、分页功能;3支持多选 官方文档: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中,默认的行高和列宽可能不足以完全显示某些单元格中的内容,特别是当内容较长时。通过调整行高和列宽,可以确保所有数据都能完整显示,避免内容被截断。合理的行高和列宽可以使表格看起来更加整洁和专业,尤其是在…...

力扣-Mysql-3278. 寻找数据科学家职位的候选人 II(中等)
一、题目来源 3278. 寻找数据科学家职位的候选人 II - 力扣(LeetCode) 二、数据表结构 表:Candidates ----------------------- | Column Name | Type | ----------------------- | candidate_id | int | | skill | varch…...

Android笔记(三十六):封装一个Matrix从顶部/底部对齐的ImageView
背景 ImageView的scaleType默认显示图片是这样,但是有时候设计稿需求希望图片左右能紧贴着ImageView左右边缘,又不破坏图片的比例,用自带的matrix,centerCrop等都可以满足 但是都会造成图片的某些区域被裁剪了,如果设…...
web 入门
学习 Web 开发的基础,建议从以下几个方面入门,按步骤循序渐进学习核心知识: 1. 了解 Web 的基础概念 在开始编码之前,先理解 Web 开发的基本工作原理: Web 前端与后端: 前端:负责用户界面和用…...
京东 2025届秋招 自然语言处理
文章目录 个人情况一面/HR面 10min二面/技术面 1h三面/技术面 1h四面/线下HR面 20min 个人情况 先说一下个人情况: 学校情况:211本中9硕,本硕学校都一般,本硕都是计算机科班,但研究方向并不是NLP,而是图表…...
Mybatis框架之模板方法模式 (Template Method Pattern)
MyBatis 中也使用到了 模板方法模式 (Template Method Pattern),主要体现在 执行 SQL 语句的流程控制 上。模板方法模式允许 MyBatis 定义数据库操作的标准流程,并允许子类或特定实现类去实现某些步骤。这种模式使得 MyBatis 能够在处理不同类型的 SQL 操…...

【进阶系列】python简单爬虫实例
python有一个很强大的功能就是爬取网页的信息,这里是CNBlogs 网站,我们将以此网站为实例,爬取指定个页面的大标题内容。代码如下: 首先是导入库: # 导入所需的库 import requests # 用于发送HTTP请求 from bs4 impor…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...

MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...