一文道破Java中的深拷贝,浅拷贝,零拷贝

前言

在Java编写代码中,对象的拷贝是一个常见的操作。根据拷贝的层次和方式不同,可以分为深拷贝、浅拷贝和零拷贝。本篇文章我们将详细介绍这三种拷贝方式的概念、实现方法以及使用场景,方便大佬学习及面试。

在这里插入图片描述

深拷贝

深拷贝是一种创建对象副本的方法,其中新对象与原始对象完全独立。这就意味着新对象的所有字段都被复制,并且如果字段是引用类型,那么递归地执行深拷贝,以确保新对象和原始对象不共享任何内部对象。

如何实现深拷贝呢,接下来介绍一下:

  1. 手动实现:通过创建一个新的对象,并逐个复制字段的值。如果字段是引用类型,需要递归地创建该字段的新实例,只不过这个过程比较繁琐。
  2. 使用序列化:将对象序列化为字节流,然后再反序列化回一个新对象。这种方法要求对象及其所有组成部分都是可序列化的。
  3. 使用克隆:实现Cloneable接口并重写clone()方法。但这种方法有争议,因为它可能不提供真正的深拷贝,除非所有相关的类都正确实现了clone()方法。

举个栗子,我们现在有简单的Person类和一个Address类:

class Address implements Serializable {  
    private String street;  
    // ... 其他属性和方法 ...  
}  
  
class Person implements Serializable {  
    private String name;  
    private Address address;  
    // ... 其他属性和方法 ...  
      
    public Person deepCopy() {  
        try {  
            // 使用序列化实现深拷贝  
            ByteArrayOutputStream baos = new ByteArrayOutputStream();  
            ObjectOutputStream oos = new ObjectOutputStream(baos);  
            oos.writeObject(this);  
            oos.close();  
              
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());  
            ObjectInputStream ois = new ObjectInputStream(bais);  
            return (Person) ois.readObject();  
        } catch (Exception e) {  
            throw new RuntimeException(e);  
        }  
    }  
}

代码解释:
不难看出,Person类有一个Address类型的字段。我们实现Serializable接口了并使用序列化和反序列化技术,可以创建一个Person对象的深拷贝。这就意味着新创建的Person对象和原始对象是完全独立的,它们不共享任何内部状态。

浅拷贝

浅拷贝创建一个新对象,并复制原始对象的所有非静态字段到新对象。但是,如果字段是引用类型,那么只复制引用而不复制引用的对象。因此,对于引用类型的字段,原始对象和新对象共享同一个内部对象。

那么实现浅拷贝呢,方法如下:

我们通常可以通过创建一个新对象,并且使用构造函数或setter方法将原始对象的值复制到新对象中来实现浅拷贝。Java中的自动装箱和拆箱机制可以简化基本数据类型的复制

Such as:

使用上面的Person和Address类为例:

class Person {  
    private String name;  
    private Address address;  
    // ... 其他属性和方法 ...  
      
    public Person shallowCopy() {  
        Person copy = new Person();  
        copy.setName(this.name); // 复制基本数据类型字段  
        copy.setAddress(this.address); // 只复制引用,不复制引用的对象  
        return copy;  
    }  
}

对上面的代码解释一下:
我们创建了一个新的Person对象并且复制基本数据类型字段的值和引用类型字段的引用来实现浅拷贝。这意味着修改新对象的name字段不会影响原始对象,但修改新对象的address字段会影响原始对象,因为它们共享同一个Address对象。

零拷贝

零拷贝是一种在数据传输过程中避免不必要的数据复制的技术。零拷贝通常与I/O操作相关,尤其是当数据从一个存储位置移动到另一个存储位置时。通过直接在内存、文件或网络之间传输数据,零拷贝技术可以减少CPU的使用和内存带宽的消耗,从而提高性能。

Java中什么地方用到了零拷贝技术呢?比如:

  • MappedByteBuffer:使用内存映射文件将文件或文件的一部分映射到内存中,从而允许直接访问文件数据而不需要将数据复制到应用程序的内存中。这可以通过FileChannel中的map()方法实现。
  • FileChannel的transferTo/transferFrom方法:这些方法允许数据直接在文件通道或套接字通道之间传输,而不需要先复制到应用程序的内存中。比如,可以使用FileChannel中的transferTo()方法将数据直接从文件发送到网络套接字。
  • DirectBuffer:通过使用直接缓冲区(DirectBuffer),数据可以直接在操作系统的原生内存中进行处理,而不需要先复制到Java堆内存中。这可以通过创建一个ByteBuffer并调用其allocateDirect()方法来实现。

如,上面就是Java的NIO库提供了一些零拷贝技术的实现方法。

try (FileChannel sourceChannel = new FileInputStream("source.txt").getChannel();  
     FileChannel destinationChannel = new FileOutputStream("destination.txt").getChannel()) {  
    destinationChannel.transferFrom(sourceChannel, 0, sourceChannel.size());  
} catch (IOException e) {  
    e.printStackTrace();  
}

我们在上面的代码中就使用FileChannel的transferFrom()方法实现了文件传输的零拷贝。数据直接从源文件通道传输到目标文件通道,而不需要先复制到应用程序的内存中。这种方法在处理大文件时可以提高性能并减少内存消耗。

文章到这里就先结束了,感兴趣的可以订阅专栏哈,后续会继续分享相关的知识点。

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构】——期末复习题题库(1)

🎃个人专栏: 🐬 算法设计与分析:算法设计与分析_IT闫的博客-CSDN博客 🐳Java基础:Java基础_IT闫的博客-CSDN博客 🐋c语言:c语言_IT闫的博客-CSDN博客 🐟MySQL&#xff1a…

数据治理之数据标准管理

目录 一、概述什么是数据标准数据标准的作用什么是数据标准化数据标准的意义业务方面技术方面管理方面 二、数据标准管理的内容数据模型标准基础数据标准主数据和参考数据标准指标数据标准 三、数据标准管理流程数据标准梳理数据标准制定数据标准审查数据标准发布数据标准贯彻 …

Redis的安装以及使用

第一步,去官网下载一个压缩包到本地解压即用,绿色软件,不用其他操作,点击Download下载即可: Introduction to Redis | RedisLearn about the Redis open source projecthttps://redis.io/docs/about/第二步&#xff0…

用邮件群发软件开拓外贸客户:有效的方法与技巧

随着跨境电商业务的发展,企业在研发外贸客户时面临如何有效地与潜在用户沟通的挑战。电子邮件群发软件已经成为一种时兴的工具,帮助企业迅速推送很多电子邮件。本文将探讨电子邮件群发软件在外贸客户开发中的实际应用效果,并从专业角度分析其…

简单的喷淋实验--嵌入式实训

目录 喷淋实验--嵌入式实训 1.MQTT通信原理 2.MQTT库的移植 3.代码流程 运行视频如下: 喷淋实验--嵌入式实训 1.MQTT通信原理 MQTT(Message Queuing Telemetry Transport)是一种轻量级的发布/订阅消息传输协议,旨在提供可靠、高效的通信…

计算机视觉基础(12)——图像恢复

前言 我们将学习图像恢复相关知识。主要有图像恢复的定义、评价标准和实现图像恢复的方法。图像恢复任务包括图像去噪、去模糊、图像超分辨率、图像修复等;评价标准有峰值信噪比和结构相似性;图像超分辨的方法有传统方法和基于深度学习的方法&#xff1a…

three.js使用精灵模型Sprite渲染森林

效果&#xff1a; 源码&#xff1a; <template><div><el-container><el-main><div class"box-card-left"><div id"threejs" style"border: 1px solid red"></div><div class"box-right&quo…

Elasticsearch基本使用

文章目录 概要一、核心概念二、索引操作2.1 创建索引2.2 判断索引是否存在2.3 查看索引2.4 打开、关闭索引2.5 删除索引 三、映射操作3.1 创建映射字段3.2 映射属性详解3.3 查看映射关系 四、文档增删改查4.1 新增文档4.2 查看单个文档4.3 查看所有文档4.4 _source定制返回字段…

Linux进阶系列(二)——lscpu、htop、seq、shuf、sort

1. lscpu lscpu 命令是Linux系统中用来显示关于CPU架构的信息的工具。它详细展示了CPU的相关信息&#xff0c;包括型号、核心数、架构类型、缓存大小等等。 1.1 物理CPU与逻辑CPU 物理CPU指的是实际存在于硬件系统上的中央处理单元。每个物理CPU都是一个独立的处理器芯片或处…

【LeetCode刷题笔记】动态规划(二)

647. 回文子串 解题思路: 1. 暴力穷举 , i 遍历 [0, N) , j 遍历 [i+1, N] ,判断每一个子串 s[i, j) 是否是回文串,判断是否是回文串可以采用 对撞指针 的方法。如果是回文串就计数 +1

C# 类型和成员

C# 教程 - 类型及其成员 - C# | Microsoft Learnhttps://learn.microsoft.com/zh-cn/dotnet/csharp/tour-of-csharp/types 目录 类和对象 类型参数 基类 结构 接口 枚举 可为 null 的类型 元组 作为面向对象的语言&#xff0c;C# 支持封装、继承和多态性这些概念。 类可…

算法——链表

链表常用技巧 画图分析&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;——直观形象&#xff0c;便于理解、大多数都是模拟引入虚拟头结点&#xff08;哨兵位&#xff09; 典型的就是在第一个节点…

Redis设计与实现之服务器与客户端

目录 一、服务器与客户端 1、初始化服务器 1. 初始化服务器全局状态 2. 载入配置文件 3. 创建 daemon 进程 4. 初始化服务器功能模块 5. 载入数据 6. 开始事件循环 2、 客户端连接到服务器 3、命令的请求、处理和结果返回 4、命令请求实例:SET 的执行过程 5、Redis服…

【浏览器】同源策略和跨域

1. 什么是跨域 在说跨域之前,先说说同源策略,什么是同源策略呢?同源策略是浏览器的一种安全机制,减少跨站点脚本攻击(XSS,Cross Site Scripting)、跨站点请求伪造(CSRF,Cross Site Request Forgery)攻击等,因为非同源的请求会被浏览器拦截掉。 同源就是协议、域名(…

电路设计(7)——窗口比较器的multism仿真

1.功能设计 构建一个窗口比较器的电路&#xff0c;在输入电压大于3.5v&#xff0c;小于0.8v时&#xff0c;蜂鸣器报警&#xff0c;输入电压在0.8v到3.5v之间时&#xff0c;不报警。 整体电路如下&#xff1a; 2.设计思路 在输入端&#xff0c;采取电阻分压的方式&#xff0c;输…

ChatGPT/GPT4+AI绘图+论文写作+编程结合到底有多强大?带你详细了解

ChatGPT在论文写作与编程方面具备强大的能力。无论是进行代码生成、错误调试还是解决编程难题&#xff0c;ChatGPT都能为您提供实用且高质量的建议和指导&#xff0c;提高编程效率和准确性。此外&#xff0c;ChatGPT是一位出色的合作伙伴&#xff0c;可以为您提供论文写作的支持…

Jenkins自动化部署之后端

准备工作参考本人另外几篇Jenkins相关的文章 新建任务 添加参数配置 字符串参数&#xff1a;分支名称 多选框&#xff1a;项目名称&#xff08;Extended Choice Parameter插件必备&#xff0c;插件安装参考我另外的文章&#xff09; 这个分割规则自定义。只要根据Jenkins…

【Java】MybatisPlus

MybatisPlus MybatisPlus是在mybatis基础上的一个增强型工具。它对mybatis的一些操作进行了简化&#xff0c;能够提高开发的效率。 springboot整合了mybatis之后&#xff0c;其实已经非常方便了&#xff0c;只需要导入mybatis的包后&#xff0c;在配置文件中编写数据源信息&a…

MySQL的替换函数及补全函数的使用

前提&#xff1a; mysql的版本是8.0以下的。不支持树形结构递归查询的。但是&#xff0c;又想实现树形结构的一种思路 提示&#xff1a;如果使用的是MySQL8.0及其以上的&#xff0c;想要实现树形结构&#xff0c;请参考&#xff1a;MySQL数据库中&#xff0c;如何实现递归查询…

渗透测试——1.2被动扫描

一、概念 目标无法觉察的情况下进行的信息收集。公开渠道可获得的信息&#xff0c;与目标系统不产生直接交互&#xff0c;尽量避免留下一切痕迹。 二、CDN&#xff08;content delivery netword内容分发网路&#xff09; 多台边缘服务器提供网络服务&#xff0c; 三、WAF&am…