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…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止
<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...
腾讯云V3签名
想要接入腾讯云的Api,必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口,但总是卡在签名这一步,最后放弃选择SDK,这次终于自己代码实现。 可能腾讯云翻新了接口文档,现在阅读起来,清晰了很多&…...
根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的----NTFS源代码分析--重要
根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的 第一部分: 0: kd> g Breakpoint 9 hit Ntfs!ReadIndexBuffer: f7173886 55 push ebp 0: kd> kc # 00 Ntfs!ReadIndexBuffer 01 Ntfs!FindFirstIndexEntry 02 Ntfs!NtfsUpda…...

一些实用的chrome扩展0x01
简介 浏览器扩展程序有助于自动化任务、查找隐藏的漏洞、隐藏自身痕迹。以下列出了一些必备扩展程序,无论是测试应用程序、搜寻漏洞还是收集情报,它们都能提升工作流程。 FoxyProxy 代理管理工具,此扩展简化了使用代理(如 Burp…...
ThreadLocal 源码
ThreadLocal 源码 此类提供线程局部变量。这些变量不同于它们的普通对应物,因为每个访问一个线程局部变量的线程(通过其 get 或 set 方法)都有自己独立初始化的变量副本。ThreadLocal 实例通常是类中的私有静态字段,这些类希望将…...

NineData数据库DevOps功能全面支持百度智能云向量数据库 VectorDB,助力企业 AI 应用高效落地
NineData 的数据库 DevOps 解决方案已完成对百度智能云向量数据库 VectorDB 的全链路适配,成为国内首批提供 VectorDB 原生操作能力的服务商。此次合作聚焦 AI 开发核心场景,通过标准化 SQL 工作台与细粒度权限管控两大能力,助力企业安全高效…...

华为云Flexus+DeepSeek征文 | MaaS平台避坑指南:DeepSeek商用服务开通与成本控制
作者简介 我是摘星,一名专注于云计算和AI技术的开发者。本次通过华为云MaaS平台体验DeepSeek系列模型,将实际使用经验分享给大家,希望能帮助开发者快速掌握华为云AI服务的核心能力。 目录 作者简介 前言 一、技术架构概览 1.1 整体架构设…...