如何使用可外部化的接口在Java中自定义序列化

在上一篇文章“用示例介绍的有关Java序列化的一切”中 ,我解释了如何使用以下方法序列化/反序列化一个对象
Serializable接口,还说明了如何使用writeObjectreadObject方法自定义序列化过程。

Java序列化过程的缺点

但是,这些定制还不够,因为JVM可以完全控制序列化过程,而这些定制逻辑只是默认序列化过程的补充。 我们仍然必须通过从writeObjectObjectInputStream.defaultReadObject()调用ObjectOutputStream.defaultWriteObject()ObjectInputStream.defaultReadObject()来使用默认的序列化逻辑。
readObject方法。 如果不调用这些默认方法,我们的对象将不会被序列化/反序列化。

默认的序列化过程是完全递归的。 因此,每当我们尝试序列化一个对象时,序列化过程都会尝试使用我们的类( staticstatic除外)对所有字段(原始和引用)进行序列化。
transient场)。 这使得序列化过程非常缓慢。

现在,我们假设我们有一个对象,其中包含很多字段,由于某些原因,我们不想序列化这些字段(这些字段将始终分配有默认值)。 在默认的序列化过程中,我们将不得不使所有这些字段都是瞬态的,但是它仍然不会高效,因为将进行大量检查以查看这些字段是否为瞬态的。

因此,如我们所见,使用默认序列化过程有很多弊端,例如:

  1. 序列化的定制是不够的,因为JVM可以完全控制序列化过程,而我们的定制逻辑只是默认序列化过程的补充。
  2. 默认序列化过程是完全递归且缓慢的。
  3. 为了不对字段进行序列化,我们必须声明它为瞬态,而很多瞬态字段将再次使过程变慢。
  4. 我们无法控制如何对字段进行序列化和反序列化。
  5. 默认序列化过程在创建对象时不会调用构造函数,因此它无法调用构造函数提供的初始化逻辑。

什么是外部化和外部化接口

正如我们在上面看到的,默认的Java序列化效率不高。 我们可以通过使用Externalizable接口而不是
Serializable接口。

我们可以通过实现
可外部化的接口并覆盖它的方法writeExternal()
readExternal() 。 但是使用这种方法,我们将无法从JVM获得任何类型的默认序列化逻辑,而是由我们来提供完整的序列化和反序列化逻辑。

因此,非常仔细地对测试这些方法进行编码非常有必要,因为这可能会破坏序列化过程。 但是,如果正确实现,与默认序列化过程相比,外部化过程非常快。

我们将以下面的Employee类对象为例进行说明:

 // Using Externalizable, complete serialization/deserialization logic becomes our responsibility,  // We need to tell what to serialize using writeExternal() method and what to deserialize using readExternal(),  // We can even serialize/deserialize static and transient variables,  // With implementation of writeExternal() and readExternal(), methods writeObject() and readObject() becomes redundant and they do not get called.  Employee class implements Externalizable { // This serialVersionUID field is necessary for Serializable as well as Externalizable to provide version control, // Compiler will provide this field if we do not provide it which might change if we modify class structure of our class, and we will get InvalidClassException, // If we provide a value to this field and do not change it, serialization-deserialization will not fail if we change our class structure. private static final long serialVersionUID = 2L; private String firstName; private transient String lastName; // Using Externalizable, we can even serialize/deserialize transient variables, so declaring fields transient becomes unnecessary. private int age; private static String department; // Using Externalizable, we can even serialize/deserialize static variables according to our need. // Mandatory to have to make our class Externalizable // When an Externalizable object is reconstructed, the object is created using public no-arg constructor before the readExternal method is called. // If a public no-arg constructor is not present then a InvalidClassException is thrown at runtime. public Employee() { } // All-arg constructor to create objects manually public Employee(String firstName, String lastName, int age, String department) { this .firstName = firstName; this .lastName = lastName; this .age = age; Employee.department = department; validateAge(); } private void validateAge() { System.out.println( "Validating age." ); if (age < 18 || age > 70 ) { throw new IllegalArgumentException( "Not a valid age to create an employee" ); } } @Override // We need to tell what to serialize in writeExternal() method public void writeExternal(ObjectOutput out) throws IOException { System.out.println( "Custom externalizable serialization logic invoked." ); out.writeUTF(firstName); out.writeUTF(lastName); out.writeInt(age); out.writeUTF(department); } @Override // We need to tell what to deserialize in readExternal() method // The readExternal method must read the values in the same sequence and with the same types as were written by writeExternal public void readExternal(ObjectInput in) throws IOException { System.out.println( "Custom externalizable serialization logic invoked." ); firstName = in.readUTF(); lastName = in.readUTF(); age = in.readInt(); department = in.readUTF(); validateAge(); } @Override public String toString() { return String.format( "Employee {firstName='%s', lastName='%s', age='%s', department='%s'}" , firstName, lastName, age, department); } // Custom serialization logic, It will be called only if we have implemented Serializable instead of Externalizable. private void writeObject(ObjectOutputStream oos) throws IOException { System.out.println( "Custom serialization logic invoked." ); } // Custom deserialization logic, It will be called only if we have implemented Serializable instead of Externalizable. private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { System.out.println( "Custom deserialization logic invoked." ); }  } 

序列化如何与可外部化接口一起工作

如上面在示例Employee类中所见,我们可以通过实现Externalizable接口并覆盖其方法writeExternal()readExternal()来编写自己的序列化逻辑。

通过调用DataOutput方法的原始值或调用ObjectOutput对象的writeObject方法的对象,字符串和数组,该对象可以实现writeExternal方法来保存其内容。

通过调用原始类型的DataInput方法和对象,字符串和数组的readObject方法,该对象可以实现readExternal方法以恢复其内容。 readExternal方法必须按与writeExternal相同的顺序和相同的类型读取值。

 // We need to tell what fields to serialize in writeExternal() method  public void writeExternal(ObjectOutput out) throws IOException { System.out.println( "Custom externalizable serialization logic invoked." ); out.writeUTF(firstName); out.writeUTF(lastName); out.writeInt(age); out.writeUTF(department);  }  // We need to tell what fields to deserialize in readExternal() method  // The readExternal method must read the values in the same sequence and with the same types as were written by writeExternal  public void readExternal(ObjectInput in) throws IOException { System.out.println( "Custom externalizable serialization logic invoked." ); firstName = in.readUTF(); lastName = in.readUTF(); age = in.readInt(); department = in.readUTF(); validateAge();  } 

要将对象序列化和反序列化为文件,我们需要遵循与Serializable示例相同的过程,这意味着调用
如以下代码所示,完成ObjectOutputStream.writeObject()ObjectInputStream.readObject()

 public class ExternalizableExample { public static void main(String[] args) throws IOException, ClassNotFoundException { Employee empObj = new Employee( "Shanti" , "Sharma" , 25 , "IT" ); System.out.println( "Object before serialization => " + empObj.toString()); // Serialization serialize(empObj); // Deserialization Employee deserializedEmpObj = deserialize(); System.out.println( "Object after deserialization => " + deserializedEmpObj.toString()); } // Serialization code static void serialize(Employee empObj) throws IOException { try (FileOutputStream fos = new FileOutputStream( "data.obj" ); ObjectOutputStream oos = new ObjectOutputStream(fos)) { oos.writeObject(empObj); } } // Deserialization code static Employee deserialize() throws IOException, ClassNotFoundException { try (FileInputStream fis = new FileInputStream( "data.obj" ); ObjectInputStream ois = new ObjectInputStream(fis)) { return (Employee) ois.readObject(); } }  } 

Externalizable接口是Serializable的子接口,即
Externalizable extends Serializable 。 因此,如果我们实现Externalizable接口并覆盖其writeExternal()
然后,将使用readExternal()方法优先于这些方法,而不是由JVM提供的默认序列化机制。 这些方法取代了writeObjectreadObject方法的定制实现,因此,如果我们还提供writeObject()readObject() ,则将忽略它们。

在序列化过程中,将针对要序列化的每个对象的Externalizable接口进行测试。 如果对象支持Externalizable,则调用writeExternal方法。 如果对象不支持Externalizable并且实现了Serializable,则使用ObjectOutputStream保存该对象。

重建Externalizable对象时,将使用公共no-arg构造函数创建一个实例,然后调用readExternal方法。 可序列化的对象通过从ObjectInputStream读取来恢复。

  1. 重建Externizable对象时,在调用readExternal方法之前,使用公共的无参数构造函数创建对象。 如果不存在公共的无参数构造函数,则在运行时引发InvalidClassException。
  2. 使用Externalizable,我们甚至可以序列化/反序列化瞬态变量,因此无需声明字段瞬态。
  3. 使用Externalizable,我们甚至可以根据需要对静态变量进行序列化/反序列化。

Externalizable实例可以通过Serializable接口中记录的writeReplace和readResolve方法指定替换对象。

Java 序列化还可以用于深度克隆对象 。 Java克隆是Java社区中最有争议的话题,它的确有其缺点,但是在对象完全满足Java克隆的强制条件之前,它仍然是创建对象副本的最流行和最简单的方法。 我在3篇文章的Java克隆系列中详细介绍了克隆 ,其中包括Java克隆和克隆类型(浅和深)等文章, 并带有示例 , Java克隆–复制构造器与克隆 , Java克隆–甚至复制构造器都不是如果您想了解更多有关克隆的知识,请充分阅读它们。

可外部化与可序列化之间的差异

让我们列出Java中Externalizable和Serializable接口之间的主要区别。

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

翻译自: https://www.javacodegeeks.com/2019/08/customize-serialization-java-using-externalizable-interface.html

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

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

相关文章

电话光端机使用什么光纤网络比较好?

电话光端机是一种将传统电话信号转换为光信号并通过光纤传输的设备&#xff0c;要使用电话光端机&#xff0c;必须首先具有光纤网络。那么电话光端机使用哪种纤维更好呢&#xff1f;接下来就让我们跟随飞畅科技的小编一起来看看吧&#xff01; 如果电话光端机使用的光纤网络在…

电话光端机原理及作用分析

常用的光端机分为多种类型&#xff0c;例如电话光端机、网络光端机、音频光端机、视频光端机、串口光端机、PDH光端机等。通常&#xff0c;电话光端机是最常用的&#xff0c;并且它们也被广泛使用。今天&#xff0c;就由光端机专业厂家飞畅科技来为大家普及下电话光端机的原理及…

关于Jakarta EE与MicroProfile的创新和关系的提案

在JCrete非会议上&#xff0c;我们中的一些人正在就Jakarta EE的愿景&#xff0c;尤其是与MicroProfile的关系进行头脑风暴。 我想开始讨论&#xff0c;以使所有人都在同一页面上&#xff0c;尤其是Jakarta EE和MicroProfile之间的关系以及Jakarta的创新应如何。 我相信我们中的…

电话光端机作用,电话光端机功能特点介绍

电话光端机顾名思义其实也是一种光端机&#xff0c;但是他不仅仅只能传输电话的光端机。它的用户接口类型多样&#xff08;包括语音、数据、图象&#xff09;&#xff0c;均以小型模块化部件方式装配到母板上&#xff0c;各种用户模块可以混合装配&#xff0c;方便扩容及维护。…

光端机的作用是什么? 简述光端机的作用

简单说光端机是光信号传输的终端设备&#xff0c;光端机一般都是成对使用&#xff0c;分为光发射机和光接收机。市面上常见的光端机主要有&#xff1a;电话光端机、PDH光端机、高清视频光端机、音频光端机、以太网光端机、数据光端机等等。那么&#xff0c;各类光端机的作用是什…

db2分页sql_停止尝试使用内部DB框架模拟SQL OFFSET分页!

db2分页sql我敢肯定&#xff0c;到目前为止&#xff0c;您已经以多种方式弄错了。 而且您可能很快将无法正确处理。 那么&#xff0c;当您可以实施业务逻辑时&#xff0c;为什么还要在SQL调整上浪费您的宝贵时间呢&#xff1f; 让我解释… 直到最近的SQL&#xff1a;2008标准 …

关于单纤与双纤光端机的区别介绍

单纤和双纤的光端机最大区别就是它们主板上的光模块区别&#xff0c;其他的地方基本上都是一样的。下面&#xff0c;飞畅科技的小编来为大家详细介绍下单纤与双纤光端机的区别&#xff0c;一起来看看吧&#xff01; 单纤光端机&#xff1a;接收与发送的数据在一根光纤上传输。…

ImportError: cannot import name ‘constants‘

运行ns3gym案例一直报这个错&#xff0c;然后重新配置了两遍环境&#xff0c;然而并没有什么用。通过Google Baidu搜索&#xff0c;建议执行以下代码 pip install --upgrade pyzmq 执行后出现以下错误 然后搜索执行代码 sudo pip3 install --ignore-installed pyzmq 安装成功…

如何在不同的浏览器中设置Selenium网格以并行执行

到目前为止&#xff0c;Selenium是最常用的Web自动化测试工具。 如此受欢迎的原因之一是Selenium的自动跨浏览器测试功能。 硒自动化测试可以帮助您在所有主要浏览器&#xff0c;所有主要操作系统甚至移动设备浏览器上进行测试。 您可以在所有功能测试中获得广泛的浏览器覆盖&a…

网管型工业交换机和 非网管型工业交换机的优缺点

工业交换机专业为达到灵便变化多端的工业生产运用要求而设计方案&#xff0c;出示一种性价比高电力线通信通讯解决方法。而工业交换机也分成网管型和非网管型二种。那么&#xff0c;网管型工业交换机和非网管型工业交换机有什么不同&#xff0c;大家该如何选择呢&#xff1f;接…

如何集成和使用EclEmma插件来获得良好的Junit覆盖率

你好朋友&#xff0c; 如果编写好的代码很重要&#xff0c;那么编写覆盖所有业务逻辑的优良Junit测试用例也同样重要。通过编写覆盖业务逻辑的Junit测试用例&#xff0c;我们实际上确保代码的每种方法都能正常工作按照预期进行&#xff0c;因此减少了在软件开发的后期阶段中获…

工业4.0时代,工业交换机在智能电网建设中有什么作用?

随着工业以太网技术、光纤技术和信息处理技术的发展&#xff0c;并向电力行业的渗透&#xff0c;在当前技术条件支持下&#xff0c;工业以太网通信在运行过程中表现出高可靠性、灵活性和扩展性等优点&#xff0c;对优化整个电网系统设备元件之间的连接和信息传输有着重要的作用…

工业交换机的性能优势有哪些?

工业交换机也称作工业以太网交换机&#xff0c;即应用于工业控制领域的以太网交换机设备&#xff0c;对工业交换机我们有多少人了解呢&#xff1f;究竟何为工业交换机&#xff0c;工业交换机有哪些功能呢&#xff1f;接下来就由飞畅科技的小编来为大家详细讲解下吧&#xff01;…

谷歌浏览器出现“远程计算机访问失败问题”

转载链接 一、进入浏览器设置 二、“internet选项”目录 三、设置 只勾选一个&#xff0c;其余均不选。 四、打开新网页&#xff0c;解决问题

工业交换机都有哪些优势,该如何挑选

相对普通交换机而言&#xff0c;工业交换机在普通交换机的基础之上加强了功能&#xff0c;端口配置和产品系列更加丰富和灵活&#xff0c;能够满足各种工业领域的需求。广泛应用于智慧交通、安防监控、风电光伏、煤矿等领域。尤其是电力、交通、冶金被称为工业交换机应用的三大…

用Java中的抽象类扩展抽象类

示例问题 当我创建Java :: Geci抽象类AbstractFieldsGenerator和AbstractFilteredFieldsGenerator我遇到了一个不太复杂的设计问题。 我想强调一下&#xff0c;对于某些人来说&#xff0c;这个问题和设计可能看起来很明显&#xff0c;但是在我最近与一位初级开发人员&#xff0…

工业交换机与工业路由器的区别

工业交换机&#xff08;也叫工业以太网交换机&#xff09;&#xff0c;即应用于工业控制领域的以太网交换机设备&#xff0c;由于采用的网络标准&#xff0c;其开放性好、应用广泛以及价格低廉、使用的是透明而统一的TCP/IP协议&#xff0c;以太网已经成为工业控制领域的主要通…

Sublime介绍安装和使用(转载)

转载&#xff1a; 原文链接&#xff1a;https://blog.csdn.net/ITTechnologyHome/article/details/80486235 1.1 Sublime介绍 Sublime是一款跨平台、收费的文件编辑器&#xff0c;可以用来编写HTML,CSS,JavaScript,PHP等应用程序。 1.2 Sublime特点 跨平台,支持主流操作系统…

工业交换机在城市智慧轨道交通中的应用分析

俗话说&#xff0c;城市建设&#xff0c;交通先行&#xff0c;轨道交通是解决“城市病”的一把金钥匙&#xff0c;而智慧交通更是建设智慧城市的重要构成部分。从2009年开始&#xff0c;我国就逐渐进入城市轨道交通建设的高潮&#xff0c;并逐年扩大地铁市场。发展以轨道交通为…

apache hive_Hive:使用Apache Hive查询客户最喜欢的搜索查询和产品视图计数

apache hive这篇文章介绍了如何使用Apache Hive查询Hadoop下存储的搜索点击数据。 我们将以示例的形式生成有关总产品浏览量的客户最爱搜索查询和统计信息。 继续之前的文章 使用大数据分析客户产品搜索点击次数 &#xff0c; Flume&#xff1a;使用Apache Flume收集客户产品…