如何在内存序列化中使用Java深克隆对象

在我以前的文章中,我解释了深度克隆和浅层克隆之间的区别 , 以及复制构造函数和防御性复制方法比默认的Java克隆更好。

使用复制构造函数和防御性复制方法进行的Java对象克隆当然具有某些优势,但是我们必须显式编写一些代码才能在所有这些方法中实现深度克隆。 而且,仍然有可能我们会错过某些东西并且不会得到深克隆的对象。

正如在Java中创建对象的5种不同方式所讨论的那样,对序列化对象进行反序列化将创建一个状态与序列化对象相同的新对象。 因此,与上述克隆方法类似,我们也可以使用对象序列化和反序列化来实现深度克隆功能,并且通过这种方法,我们不必担心或编写用于深度克隆的代码,默认情况下会得到它。

但是,使用序列化克隆对象会带来一些性能开销,如果我们只需要克隆对象而不需要将其持久保存在文件中以备将来使用,则可以通过使用内存中序列化来改进它。

我们将使用以下Employee类作为示例,其name
作为状态的dojskills ,对于深度克隆,我们无需担心code> name字段,因为它是String对象,默认情况下是all
弦在本质上是不变的 。

您可以在《 如何在Java中创建不可变的类》以及《 为什么String是不可变的和Final》上阅读有关不可变性的更多信息。

 Employee class implements Serializable { private static final long serialVersionUID = 2L; private String name; private LocalDate doj; private List<String> skills; public Employee(String name, LocalDate doj, List<String> skills) { this .name = name; this .doj = doj; this .skills = skills; } public String getName() { return name; } name; } public LocalDate getDoj() { return doj; } doj; } public List<String> getSkills() { return skills; } skills; } // Method to deep clone a object using in memory serialization public Employee deepClone() throws IOException, ClassNotFoundException { // First serializing the object and its state to memory using ByteArrayOutputStream instead of FileOutputStream. ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(bos); out.writeObject( this ); // And then deserializing it from memory using ByteArrayOutputStream instead of FileInputStream. // Deserialization process will create a new object with the same state as in the serialized object, ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream in = new ObjectInputStream(bis); return (Employee) in.readObject(); } @Override public String toString() { return String.format( "Employee{name='%s', doj=%s, skills=%s}" , name, doj, skills); } @Override public boolean equals(Object o) { if ( this == o) return true ; if (o == null || getClass() != o.getClass()) return false ; Employee employee = (Employee) o; return Objects.equals(name, employee.name) && Objects.equals(doj, employee.doj) && Objects.equals(skills, employee.skills); } @Override public int hashCode() { return Objects.hash(name, doj, skills); }  } 

为了深度克隆Employee类的对象,我提供了一个
deepClone()方法,通过使用将对象序列化到内存
ByteArrayOutputStream而不是FileOutputStream并使用ByteArrayInputStream而不是FileInputStream将其反序列化。 在这里,我们将对象序列化为字节,然后再次将其从字节反序列化为对象。

Employee类实现Serializable接口来实现序列化,这有其自身的缺点,我们可以通过使用Externalizable接口自定义序列化过程来克服其中的一些缺点。

我们可以在下面的测试中运行,以了解我们的克隆方法是深层克隆还是浅层克隆,此处所有==操作将返回false(因为两个对象是分开的),而所有equals将返回true(因为两者具有相同的内容)。

 public static void main(String[] args) throws IOException, ClassNotFoundException { Employee emp = new Employee( "Naresh Joshi" , LocalDate.now(), Arrays.asList( "Java" , "Scala" , "Spring" )); System.out.println( "Employee object: " + emp); // Deep cloning `emp` object by using our `deepClone` method. Employee clonedEmp = emp.deepClone(); System.out.println( "Cloned employee object: " + clonedEmp); System.out.println(); // All of this will print false because both objects are separate. System.out.println(emp == clonedEmp); System.out.println(emp.getDoj() == clonedEmp.getDoj()); System.out.println(emp.getSkills() == clonedEmp.getSkills()); System.out.println(); // All of this will print true because `clonedEmp` is a deep clone of `emp` and both have the same content. System.out.println(Objects.equals(emp, clonedEmp)); System.out.println(Objects.equals(emp.getDoj(), clonedEmp.getDoj())); System.out.println(Objects.equals(emp.getSkills(), clonedEmp.getSkills()));  } 

我们知道反序列化过程每次都会创建一个新对象,如果我们必须使我们的类单身,那将是不好的。 这就是为什么我们需要重写和禁用单例类的序列化,这可以通过提供writeReplace和readResolve方法来实现。

与序列化类似,Java克隆也不能与单例模式一起使用,这就是为什么我们也需要覆盖和禁用它。 我们可以通过实现克隆的方式来做到这一点,以便它要么抛出
CloneNotSupportedException或每次都返回相同的实例。

您可以在Java Cloning和Java上阅读有关Java克隆和序列化的更多信息。
Java序列化主题。

您可以在此找到本文的完整源代码。
Github存储库 ,请随时提供宝贵的反馈。

翻译自: https://www.javacodegeeks.com/2019/08/deep-clone-using-java-memory-serialization.html

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

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

相关文章

复制网页内容

问题背景&#xff1a; 当网页复制东西时&#xff0c;可能因为某些原因导致无法复制。可以用以下方法解决 解决方法&#xff1a; 1. 按下F12&#xff0c;出现以下内容 2. 依次点击右上角三个点&#xff0c;弹出界面后点击shortcuts 3. 选择首选项后&#xff0c;选中Disable …

插入时间信息

问题描述 在进行文本编辑的时候&#xff0c;往往需要记录当天日期。而Typora等软件没有及时插入时间的快捷方式。 方法 搜狗收入法提供快速记录时间的方式 1. 在中文输入法模式中输入rq&#xff08;汉语拼音日期的首字母&#xff09;&#xff0c;选项卡自动显示今日日期,可…

activemq网络桥接_ActiveMQ –经纪人网络解释–第4部分

activemq网络桥接在前面的第3部分中 &#xff0c;我们已经看到ActiveMQ如何帮助将远程使用者与本地使用者区分开来&#xff0c;这有助于确定从消息生产者到使用者的较短路径。 在第4部分中&#xff0c;我们将研究如何在远程代理上负载均衡并发使用者。 让我们考虑一些高级配置…

sublime 添加注释模块

问题背景&#xff1a; 规范的程序需要对函数进行注释&#xff0c;常用的开发工具如IDEA、VS Code都对注释模板有很好的支持。本博客介绍Sublime下支持模块注释功能的设置。 一 安装 一、安装方法 1.安装docblocker插件 mac CmdShiftP -> Install Package -> docblock…

只读副本和Spring Data第3部分:配置两个实体管理器

我们之前的设置可以正常工作。 我们现在要做的是进一步发展&#xff0c;并配置两个单独的实体管理器&#xff0c;而不会影响我们之前实现的功能。 第一步是将默认的实体管理器配置设置为主要配置。 这是第一步 package com.gkatzioura.springdatareadreplica.config; import…

Win+E快速打开我的电脑方式设置方式

W10运用快捷键WinE快速打开我的电脑设置方式

JMetro版本11.6.5和8.6.5发布

再一次问好。 设置了SDK中所有JavaFX控件的样式以及其他一些不存在的样式以及其他库中的其他样式。 后续版本将涉及调整JMetro现有样式或从第三方库的其他控件添加其他样式。 此版本就是这种情况。 这是新功能&#xff1a; 3种新的控件样式&#xff1b; 调整JMetro现有样式&a…

Chrome浏览器的便捷使用方式

截取转载于B站视频【全套教程】高效玩转Chrome浏览器&#xff0c;丰富你的上网体验_哔哩哔哩_bilibili中的脑图文件&#xff0c;便于之后的熟悉使用。 脑图链接 https://naotu.baidu.com/file/5a5332eee10dd903cc084d49189cd2behttps://naotu.baidu.com/file/5a5332eee10dd90…

Sublime查看已经安装的插件

蓝色框图内显示已经安装的插件

activemq网络桥接_ActiveMQ –经纪人网络解释–第3部分

activemq网络桥接现在&#xff0c;我们已经在本博客系列的第1部分和第2 部分中了解了ActiveMQ网络连接器的基础&#xff0c;在第3部分中&#xff0c;我们将研究ActiveMQ如何平衡连接到代理网络的使用者。 介绍 当可以无序处理队列中的消息时通常使用并发使用者&#xff0c;通常…

Word样式的导入与导出

1 样式的介绍 样式&#xff0c;也就是Word中各级标题的格式。合理的设置样式模板&#xff0c;可以帮助更方便的进行文本编辑。 2 样式的导入 具体情形为将“文档标准模板.dotm”的内容应用于“新建Microsoft Word文档”。 按照图示进行操作 【 如果应用模板为文件内的样式…

word将一个文档的样式导入到另一个文档

一、背景 在word中编辑文档时&#xff0c;经常需要定义一个样式给特定格式的文本使用&#xff0c;如标题1&#xff0c;标题2等&#xff0c;而有时需要在一个新文档A中使用一个旧文档B中定义好的样式。 二、操作步骤 1、打开旧文档B&#xff0c;选择上方标签栏的"样式&quo…

Spring Boot应用程序浪费了内存

内存是当今世界上被广泛浪费的资源之一。 由于编程效率低下&#xff0c;令人吃惊的&#xff08;有时是“令人震惊的”&#xff09;内存浪费被浪费了。 我们看到这种模式在多个企业应用程序中重复出现。 为了证明这种情况&#xff0c;我们进行了一项小型研究。 我们分析了著名的…

Win10灵活使用快速访问

I 快速访问视图 位置在winE 左侧窗口&#xff0c;点击可快速到达某个特定的文件夹。作用类似于快捷方式&#xff0c;操作简单。 II 关闭自动添加 默认是显示经常使用的文件夹。这使得窗口内文件夹较乱。 通过以下设置&#xff0c;关闭自动显示 1. 2.把框内√去掉 III 固定文…

activemq网络桥接_ActiveMQ –经纪人网络解释–第2部分

activemq网络桥接在此博客中&#xff0c;我们将看到双工网络连接器如何工作。 在上一部分中&#xff0c;我们从broker-1和broker-2创建了一个网络连接器。 我们能够看到&#xff0c;当代理2上有一个使用者使用队列“ foo.bar”时&#xff0c;代理1上的队列“ foo.bar”的消息如…

Apache Lucene中的并发查询执行

Apache Lucene是一个出色的并发纯Java搜索引擎&#xff0c;如果您愿意&#xff0c;它可以轻松地使服务器上的可用CPU或IO资源饱和。 “典型” Lucene应用程序的并发模型在搜索时每个查询一个线程&#xff0c;但是您知道Lucene还可以使用多个线程同时执行一个查询以大大减少最慢…

Windows设置自己的程序开机自动启动

Windows系统想要快速设置开机自动启动某个程序&#xff0c;可以使用以下方法设置&#xff1a; 1.找到启动文件夹 CtrlR 打开运行&#xff0c;输入shell:startup&#xff0c;回车,找到启动文件夹 2.拷贝需要开机启动的程序的快捷方式到此文件夹即可。 3.打开任务管理器-启动查…

Citavi中文件管理

目录 I 文献相对应的PDF文件相关操作 1 打开PDF所在位置 2 直接重命名PDF文献 注&#xff1a;设置角标方式 II 阅读文献相关的文件的添加与删除 1 添加 2 删除 III PPT CAJ文件的添加 I 文献相对应的PDF文件相关操作 PDF文件可直接拉入文献框进行导入 1 打开PDF所在位置…

Citavi插件的安装和使用以及注意事项

【文章转载于知乎大神&#xff1a;Citavi插件的安装和使用以及注意事项 - 知乎】 没有软件是十全十美的&#xff0c;基础功能够用&#xff0c;附加功能以插件、脚本的方式来支持是个不错的思路。 Citavi提供了自定义宏和插件的方式&#xff0c;来满足更为复杂的格式修整和文献…

MiUI特色功能设置总结

一 常用设置 【转载于知乎https://www.zhihu.com/question/514792652/answer/2377622710】 1 自动优化系统 其实在手机开发者模式设置中&#xff0c;有2个地方我们需要设置&#xff0c;设置了不仅可以让手机运行更流畅&#xff0c;而且还能帮我们自动优化系统。 &#xff0…