Java 深度复制对象:从基础到实战

目录

    • 一、深度复制的概念
    • 二、实现深度复制的方法
      • 1. 使用序列化
      • 2. 手动实现深度复制
    • 三、总结

在 Java 编程中,对象的复制是一个常见的需求。然而,简单的复制操作(如直接赋值)只会复制对象的引用,而不是创建一个新的对象。这意味着两个引用会指向同一个内存地址,修改其中一个对象会影响另一个对象。为了解决这个问题,我们需要实现对象的深度复制。本文将详细介绍如何在 Java 中实现对象的深度复制,并通过具体代码示例帮助你更好地理解和应用这一技术。

一、深度复制的概念

深度复制是指创建一个新对象,并将原对象的所有字段值复制到新对象中。如果字段是基本数据类型,则直接复制其值;如果字段是引用类型,则需要递归地创建该引用对象的深度副本。这样可以确保新对象与原对象在内存中完全独立,修改其中一个不会影响另一个。

二、实现深度复制的方法

1. 使用序列化

Java 的序列化机制可以将对象转换为字节流,然后再将字节流还原为对象。这一过程实际上创建了一个对象的深度副本。

import java.io.*;public class DeepCloneExample implements Serializable {private String name;private TransientData transientData;public DeepCloneExample(String name, TransientData transientData) {this.name = name;this.transientData = transientData;}public String getName() {return name;}public TransientData getTransientData() {return transientData;}@Overridepublic String toString() {return "DeepCloneExample{" +"name='" + name + '\'' +", transientData=" + transientData +'}';}public static DeepCloneExample deepClone(DeepCloneExample obj) throws IOException, ClassNotFoundException {ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);objectOutputStream.writeObject(obj);objectOutputStream.close();ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);DeepCloneExample clonedObj = (DeepCloneExample) objectInputStream.readObject();objectInputStream.close();return clonedObj;}
}class TransientData implements Serializable {private int value;public TransientData(int value) {this.value = value;}@Overridepublic String toString() {return "TransientData{" +"value=" + value +'}';}
}

2. 手动实现深度复制

对于某些复杂对象,手动实现深度复制可能更高效。这需要为每个需要复制的对象编写自定义的 clone 方法。

public class DeepCopyExample {private int id;private String name;private Address address;public DeepCopyExample(int id, String name, Address address) {this.id = id;this.name = name;this.address = address;}public DeepCopyExample deepCopy() {Address copiedAddress = new Address(this.address.getStreet(), this.address.getCity());return new DeepCopyExample(this.id, this.name, copiedAddress);}@Overridepublic String toString() {return "DeepCopyExample{" +"id=" + id +", name='" + name + '\'' +", address=" + address +'}';}public static void main(String[] args) {Address originalAddress = new Address("123 Main St", "Anytown");DeepCopyExample original = new DeepCopyExample(1, "Example", originalAddress);DeepCopyExample copy = original.deepCopy();System.out.println("Original: " + original);System.out.println("Copy: " + copy);original.getAddress().setCity("New City");System.out.println("After changing original's address city:");System.out.println("Original: " + original);System.out.println("Copy: " + copy);}
}class Address {private String street;private String city;public Address(String street, String city) {this.street = street;this.city = city;}public String getStreet() {return street;}public void setStreet(String street) {this.street = street;}public String getCity() {return city;}public void setCity(String city) {this.city = city;}@Overridepublic String toString() {return "Address{" +"street='" + street + '\'' +", city='" + city + '\'' +'}';}
}

三、总结

深度复制是 Java 编程中一个重要的概念,它可以确保对象的独立性,避免意外的修改。通过本文的介绍,我们学习了两种实现深度复制的方法:使用序列化和手动实现。每种方法都有其适用场景和优缺点。在实际开发中,选择合适的方法来实现对象的深度复制,可以提高代码的健壮性和可维护性。

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

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

相关文章

C++ Primer 交换操作

欢迎阅读我的 【CPrimer】专栏 专栏简介:本专栏主要面向C初学者,解释C的一些基本概念和基础语言特性,涉及C标准库的用法,面向对象特性,泛型特性高级用法。通过使用标准库中定义的抽象设施,使你更加适应高级…

FFmpeg-chapter7和chapter8-使用 FFmpeg 解码视频(原理篇和实站篇)

解码流程如下图 流程:首先,通过 avcodec_alloc_context3(nullptr) 分配一个 AVCodecContext 结构体,然后使用 avcodec_parameters_to_context 将参数复制到上下文中,接着通过 avcodec_find_decoder 查找指定的解码器,并…

2025 docker安装TiDB数据库

1.确保安装了docker和docker-compose sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-composesudo chmod x /usr/local/bin/docker-compose2.编写 Docker Compose 文…

定制化开发的WooCommerce独立站商城更安全

定制化开发的WooCommerce独立站商城在安全性、交易风险控制以及整体用户体验方面有显著优势。以下是定制化开发在这些方面的具体表现: 1. 安全性更高 定制化开发允许开发者从底层架构开始设计和优化,确保网站的安全性。以下是具体表现: (1…

CSS【实战】模拟 html 的 title 属性(鼠标悬浮显示提示文字)

效果 原理 提示内容的定位&#xff1a;子绝父相鼠标悬浮前&#xff0c;提示内容visibility: hidden;通过 :hover 触发鼠标悬浮样式&#xff0c;提示内容变为 visibility: visible; 代码 <!DOCTYPE html> <html lang"en"><head><meta charset&qu…

K8s控制器Deployment详解

回顾 ReplicaSet 控制器,该控制器是用来维护集群中运行的 Pod 数量的&#xff0c;但是往往在实际操作的时候&#xff0c;我们反而不会去直接使用 RS&#xff0c;而是会使用更上层的控制器&#xff0c;比如说 Deployment。 Deployment 一个非常重要的功能就是实现了 Pod 的滚动…

【MYSQL数据库异常处理】执行SQL语句报超时异常

MYSQL执行SQL语句异常&#xff1a;The last packet successfully received from the server was 100,107 milliseconds ago. The last packet sent successfully to the server was 100,101 milliseconds ago. 这个错误表明 MySQL 服务器与 JDBC 连接之间的通信超时了。通常由…

HJ C++11 Day2

Initializer Lists 对于一个类P class P{P(int a, int b){cout << "P(int, int), a" << a << ", b " << b << endl;}P(initializer_list<int> initlist){cout << "P(initializer_list<int>), val…

树莓派5首次开机保姆级教程(无显示器通过VNC连接树莓派桌面)

第一次开机详细步骤 步骤一&#xff1a;树莓派系统烧录1 搜索打开烧录软件“Raspberry Pi Imager”2 选择合适的设备、系统、SD卡3 烧录配置选项 步骤二&#xff1a;SSH远程树莓派1 树莓派插电2 网络连接&#xff08;有线或无线&#xff09;3 确定树莓派IP地址 步骤三&#xff…

装饰器模式--RequestWrapper、请求流request无法被重复读取

目录 前言一、场景二、原因分析三、解决四、更多 前言 曾经遇见这么一段代码&#xff0c;能看出来是把request又重新包装了一下&#xff0c;核心信息都不会改变 后面了解到这叫 装饰器模式&#xff08;Decorator Pattern&#xff09; &#xff1a;也称为包装模式(Wrapper Pat…

大语言模型进化论:从达尔文到AI的启示与展望

文章大纲 引言大语言模型中的“进化论”思想体现遗传变异过度繁殖和生存斗争大模型“过度繁殖”与“生存竞争”机制解析**一、过度繁殖:技术迭代的指数级爆发****二、生存竞争:计算资源的达尔文战场****三、生存竞争胜出关键要素****四、行业竞争格局演化趋势**核心结论自然选…

监听 RabbitMQ 延时交换机的消息数、OpenFeign 路径参数传入斜杠无法正确转义

背景 【MQ】一套为海量消息和高并发热点消息&#xff0c;提供高可用精准延时服务的解决方案 我现在有一个需求&#xff0c;就是监听 RabbitMQ 一个延时交换机的消息数&#xff0c;而 RabbitTemplate 是不存在对应的方法来获取的。 而我们在 RabbitMQ 的控制台却可以发现延时交…

分布式网络

分布式网络&#xff08;Distributed Network&#xff09;指的是一种计算机网络架构&#xff0c;其中计算资源&#xff08;计算、存储、数据处理等&#xff09;分布在多个物理或逻辑上的节点上&#xff0c;而不是集中在单一的服务器或数据中心中。这种架构的主要目标是提高系统的…

【Elasticsearch】Elasticsearch 中使用 HDFS 存储快照

在 Elasticsearch 中使用 HDFS 存储快照的步骤如下&#xff1a; 1.安装 HDFS 插件 要使用 HDFS 存储 Elasticsearch 的索引快照&#xff0c;需要在 Elasticsearch 集群的所有节点上安装 HDFS 插件。 • 在线安装&#xff1a;适用于网络环境良好的场景&#xff0c;执行以下命…

浅谈 DeepSeek 对 DBA 的影响

引言&#xff1a; 在人工智能技术飞速发展的背景下&#xff0c;DeepSeek 作为一款基于混合专家模型&#xff08;MoE&#xff09;和强化学习技术的大语言模型&#xff0c;正在重塑传统数据库管理&#xff08;DBA&#xff09;的工作模式。通过结合其强大的自然语言处理能力、推理…

STM32F4 UDP组播通信:填一填ST官方HAL库的坑

先说写作本文的原因&#xff0c;由于开项目开发中需要用到UDP组播接收的功能&#xff0c;但是ST官方没有提供合适的参考&#xff0c;使用STM32CubeMX生成的代码也是不能直接使用的&#xff0c;而我在网上找了一大圈&#xff0c;也没有一个能够直接解决的方案&#xff0c;deepse…

leetcode日记(85)验证二叉搜索树

不难&#xff0c;有两种解法&#xff08;看答案才想到中序遍历&#xff09;。 我用的是普通递归&#xff0c;和上一题差不多&#xff0c;规定min和max&#xff0c;每次遍历缩小范围: /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNod…

如何在rust中解析 windows 的 lnk文件(快捷方式)

一、从标题二开始看&#x1f601; 这些天在使用rust写一个pc端应用程序&#xff0c;需要解析lnk文件获取lnk的图标以及原程序地址&#xff0c;之前并没有过pc端应用程序开发的经验&#xff0c; 所以在广大的互联网上游荡了两天。额&#x1f97a; 今天找到了这个库 lnk_parse很…

启动wsl里的Ubuntu24报错:当前计算机配置不支持 WSL2,HCS_E_HYPERV_NOT_INSTALLED

问题&#xff1a;启动wsl里的Ubuntu24报错 报错信息&#xff1a; 当前计算机配置不支持 WSL2。 请启用“虚拟机平台”可选组件&#xff0c;并确保在 BIOS 中启用虚拟化。 通过运行以下命令启用“虚拟机平台”: wsl.exe --install --no-distribution 有关信息&#xff0c;请访…

Python使用FastAPI结合Word2vec来向量化200维的语言向量数值

准备 pip install fastapi>0.68.0 pip install uvicorn[standard]>0.15.0 pip install gensim>4.0.0 pip install jieba>0.42.1 pip install numpy>1.21.0 pip install scikit-learn>1.0.0少了的就直接补充就好 代码 from fastapi import FastAPI, HTTPExc…