在Java中,如何实现对象的拷贝?

开发中可以使用第三方库如Apache Commons Lang的SerializationUtils类或Google的Guava库来实现对象的深拷贝。这些库提供了更加灵活和方便的深拷贝实现方式,同时也提供了更多的自定义选项和错误处理机制。

在Java中,对象的拷贝可以分为浅拷贝(shallow copy)和深拷贝(deep copy)。

  1. 「浅拷贝」:
  • 创建一个新对象,然后将原始对象中的非静态字段复制到新对象,如果字段是值类型,那么对该字段执行逐位复制。如果字段是引用类型,则复制引用但不复制引用的对象。因此,原始对象及其副本引用同一个对象。
  • 在Java中,我们可以通过实现Cloneable接口并重写clone()方法来实现浅拷贝。需要注意的是,Object类中的clone()方法是受保护的,所以我们需要在我们的类中将其重写为public。
  • 另外,如果对象的字段也是需要拷贝的复杂对象,那么可能需要在这些类中也实现Cloneable接口并重写clone()方法。
  1. 「深拷贝」:
  • 创建一个新对象,然后将原始对象中的非静态字段复制到新对象。如果字段是值类型,那么对该字段执行逐位复制。如果字段是引用类型,则递归地复制该字段引用的对象,而不是只复制引用。

  • 在Java中,深拷贝通常需要我们自己写代码来实现,因为Java并没有提供直接实现深拷贝的内置方法。

  • 深拷贝的一个常见实现方式是使用序列化。我们可以将对象写入到一个流中,然后再从流中读取出来,这样得到的就是原对象的一个深拷贝。但是这种方法有一些限制,比如被拷贝的对象以及它引用的所有对象都必须是可序列化的。

注意:Cloneable接口和clone()方法的设计在Java社区中常常被认为是有缺陷的,因为它们有很多问题,比如Cloneable接口没有定义任何方法(它是一个标记接口),clone()方法的访问修饰符是protected,而且它使用的是浅拷贝,这可能会导致意外的对象共享问题。因此,在实际编程中,很多开发者更倾向于自己写代码来实现对象的拷贝,而不是使用Cloneable接口和clone()方法。

  1. 通过实现Cloneable接口并重写clone()方法来实现浅拷贝

我们定一个实体类People,实现了Cloneable接口,并且重写了clone()方法当然也是直接调用的父类的clone()方法。

复制

public class People implements Cloneable {private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overrideprotected People clone() throws CloneNotSupportedException {return (People) super.clone();}@Overridepublic String toString() {return "People{" +"name='" + name + '\'' +", age=" + age +'}';}
}

测试拷贝:

复制

public class Main {public static void main(String[] args) {People people = new People();people.setName("Reathin");people.setAge(30);System.out.println("原People" + people.toString());try {People people1 = people.clone();System.out.println("拷贝People" + people1);} catch (CloneNotSupportedException e) {throw new RuntimeException(e);}}
}

输出结果如下,我们实现了一次浅拷贝。

图片

  1. 通过将原始对象中的非静态字段复制到新对象实现深拷贝

复制

People people2 = new People();
people2.setName(people.getName());
people2.setAge(people.getAge());
System.out.println("深拷贝对象1" + people2);
  1. 通过序列化对象流实现深拷贝

复制

// 序列化对象到字节数组
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(people);
byte[] serializedData = byteArrayOutputStream.toByteArray();// 从字节数组中反序列化对象以创建深拷贝
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(serializedData);
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
People people3 = (People) objectInputStream.readObject();
System.out.println("深拷贝对象2" + people3);

最终输出结果如下:

图片

完整示例代码:

复制

public class People implements Cloneable, Serializable {private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overrideprotected People clone() throws CloneNotSupportedException {return (People) super.clone();}@Overridepublic String toString() {return "People{" +"name='" + name + '\'' +", age=" + age +'}';}
}

复制

public class Main {public static void main(String[] args) throws IOException, ClassNotFoundException, CloneNotSupportedException {People people = new People();people.setName("Reathin");people.setAge(30);System.out.println("原People" + people.toString());People people1 = people.clone();System.out.println("浅拷贝People" + people1);//深拷贝方式一People people2 = new People();people2.setName(people.getName());people2.setAge(people.getAge());System.out.println("深拷贝对象1" + people2);//深拷贝方式2// 序列化对象到字节数组ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);objectOutputStream.writeObject(people);byte[] serializedData = byteArrayOutputStream.toByteArray();// 从字节数组中反序列化对象以创建深拷贝ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(serializedData);ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);People people3 = (People) objectInputStream.readObject();System.out.println("深拷贝对象2" + people3);}
}

开发中可以使用第三方库如Apache Commons Lang的SerializationUtils类或Google的Guava库来实现对象的深拷贝。这些库提供了更加灵活和方便的深拷贝实现方式,同时也提供了更多的自定义选项和错误处理机制。

技术前沿拓展

前端开发,你的认知不能仅局限于技术内,需要发散思维了解技术圈的前沿知识。细心的人会发现,开发内部工具的过程中,大量的页面、场景、组件等在不断重复,这种重复造轮子的工作,浪费工程师的大量时间。

介绍一款程序员都应该知道的软件JNPF快速开发平台,很多人都尝试用过它,它是功能的集大成者,任何信息化系统都可以基于它开发出来。

这是一个基于 Java Boot/.Net Core 构建的简单、跨平台快速开发框架。前后端封装了上千个常用类,方便扩展;集成了代码生成器,支持前后端业务代码生成,实现快速开发,提升工作效率;框架集成了表单、报表、图表、大屏等各种常用的 Demo 方便直接使用;后端框架支持 Vue2、Vue3。如果你有闲暇时间,可以做个知识拓展。

看完本文如果觉得有用,记得点个赞支持,收藏起来说不定哪天就用上啦~

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

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

相关文章

增加Vscode引用路径

增加Vscode引用路径 增加Vscode引用路径问题说明解决思路1在Vscode中进行配置缺点 解决思路2 增加Vscode引用路径 问题说明 在嵌入式开发中需要经常用到库函数(SPL), Vscode需要配置引用路径才能对函数名或变量进行跳转 解决思路1 与Keil5 MDK类似, 在配置C/C的json文件中添…

容器和虚拟机的对比

容器和虚拟机的对比 容器和虚拟机在与硬件和底层操作系统交互的方式上有所不同 虚拟化 使多个操作系统能够同时在一个硬件平台上运行。 使用虚拟机监控程序将硬件分为多个虚拟硬件系统,从而允许多个操作系统并行运行。 需要一个完整的操作系统环境来支持该应用。…

SpringBoot内置工具类

Collections java.util包下的Collections类&#xff0c;该类主要用于操作集合或者返回集合 一、排序 List<Integer> list new ArrayList<>();list.add(2);list.add(1);list.add(3);Collections.sort(list);//升序System.out.println(list);Collections.reverse(…

React一学就会(7): 细说redux及其应用

不知不觉一个星期结束了&#xff0c;很快就要过年了&#xff0c;中间休息了两天&#xff0c;小孩生病&#xff0c;我也有点感冒了&#xff0c;还好&#xff0c;我的这个 React 基础教学课程也基本结束了。大家有不明白的可以留言问我&#xff0c;我一定竭尽所能的帮助你。后面几…

leetcode刷题(剑指offer) 79.单词搜索

79.单词搜索 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 单词必须按照字母顺序&#xff0c;通过相邻的单元格内的字母构成&#xff0c;其中“相邻”单元格是那些水…

如何在Win系统安装Jupyter Notbook并实现无公网ip远程访问本地笔记

文章目录 1.前言2.Jupyter Notebook的安装2.1 Jupyter Notebook下载安装2.2 Jupyter Notebook的配置2.3 Cpolar下载安装 3.Cpolar端口设置3.1 Cpolar云端设置3.2.Cpolar本地设置 4.公网访问测试5.结语 1.前言 在数据分析工作中&#xff0c;使用最多的无疑就是各种函数、图表、…

数字与数学高频问题(算法村第十三关白银挑战)

数组实现加法专题 数组实现整数加法 66. 加一 - 力扣&#xff08;LeetCode&#xff09; 给定一个由 整数 组成的 非空 数组所表示的非负整数&#xff0c;在该数的基础上加一。 最高位数字存放在数组的首位&#xff0c; 数组中每个元素只存储单个数字。 你可以假设除了整数…

软件测试人员常用的功能测试方法分享

功能测试就是对产品的各功能进行验证&#xff0c;根据功能测试用例&#xff0c;逐项测试&#xff0c;检查产品是否达到用户要求的功能。 常用的测试方法如下&#xff1a; 1. 页面链接检查 每一个链接是否都有对应的页面&#xff0c;并且页面之间切换正确。 2. 相关性检查 删除/…

[k8s系列]:kubernetes·概念入门

文章目录 序言1 kubernetes概述1.1 kubernetes解决的问题1.1.1 部署方式的演变1.1.2 容器化部署——容器编排问题 1.2 kubernetes组件1.2.1 kubernetes组件调用关系1.2.2 调用逻辑示例 序言 序言&#xff1a;本文将从&#xff0c;第一节&#xff1a;kubernetes解决的问题、组件…

【网络】WireShark过滤 | WireShark实现TCP三次握手和四次挥手

目录 一、开启WireShark的大门 1.1 WireShark简介 1.2 常用的Wireshark过滤方式 二、如何抓包搜索关键字 2.1 协议过滤 2.2 IP过滤 ​编辑 2.3 过滤端口 2.4 过滤MAC地址 2.5 过滤包长度 2.6 HTTP模式过滤 三、ARP协议分析 四、WireShark之ICMP协议 五、TCP三次握…

【hcie-cloud】【23】容器编排【k8s】【Kubernetes常用工作负载、Kubernetes调度器简介、Helm简介、缩略词】【下】

文章目录 单机容器面临的问题、Kubernetes介绍与安装、Kubernetes对象的基本操作、Kubernetes YAML文件编写基础Kubernetes常用工作负载Kubernetes常用工作负载简介创建一个无状态nginx集群无状态工作负载Deployment说明无状态工作负载Deployment常见操作创建一个有状态的MySQL…

MySQL解决 恢复从备份点到灾难点之间数据恢复

CSDN 成就一亿技术人&#xff01; 今天分享一期 mysql中 备份之后发生灾难造成数据丢失 那么如何恢复中间的数据呢&#xff1f; 数据库数据高于一切&#xff08;任何数据是不能丢失的&#xff09; CSDN 成就一亿技术人&#xff01; 目录 1.准备测试数据库 2.备份数据库 观…