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方法来保存其内容。

该对象可以实现readExternal方法来恢复其内容,方法是为原始类型调用DataInput的方法,为对象,字符串和数组调用readObject的方法。 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对象时,将使用公共的无参数构造函数创建一个实例,然后调用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

java自定义外部接口

java自定义外部接口_如何使用可外部化的接口在Java中自定义序列化相关推荐

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

    在上一篇文章"用示例介绍的有关Java序列化的一切"中 ,我解释了如何使用以下方法序列化/反序列化一个对象 Serializable接口,还说明了如何使用writeObject和r ...

  2. 英特尔核显自定义分辨率_如何在新版英特尔核芯显卡控制面板中自定义显示器分辨率...

    在新版本的英特尔核芯显卡控制面板中,界面和以前相比有了很大的改变.很多用户可能不太适应怎么在英特尔核芯显卡控制面板中进行相关的设置.下面由系统城小编具体和大家介绍一下如何在新版英特尔核芯显卡控制面板中 ...

  3. java syn包_月薪3K的后端面试点-网络与Java

    网络基础 传输控制协议TCP简介 面向连接的.可靠的.基于字节流的传输层通信协议 将应用层的数据流分割成报文段并发送给目标节点的TCP层 数据包都有序号,对方收到则发送ACK确认,未收到则重传 使用校 ...

  4. java游戏面试_作为一个面试官,我会问初级java工程师哪些问题?

    初级java工程师多数是刚毕业或者工作1,2年的新人.对于新人,面试中基础问题会问道很多,因为先要考察这个人的基础. 关于基础类的题目,我在面试初级java工程师的时候一般会问下面两大类问题,每类5个 ...

  5. java源码导入eclipse_如何导入外部的源码到eclipse中

    用struts,spring等框架开发也有两年的时间了,一直很少去阅读其源码,每次在eclipse编码的过程中想要看某一个类的源码,ctrl点击总是出现source not found的提示,也没有去 ...

  6. opencv3 java开发手册_介绍一本opencv不错的书-OpenCV3使用Java开发手册

    你们好 http://www.topteam.cc/02-shop-detail.php?cid=&sid=&pid=896 Opencv 不但有趣并且是免费的视觉相关开发软体,它可以 ...

  7. java游戏英雄_【技巧攻略】教你用JAVA来玩《百万英雄》答题~

    <百万英雄>是一档全民知识互动游戏,在<百万英雄>里每场12道题目全部回答正确的人,将瓜分奖金. 后续更新在我的github上,欢迎大牛前来P.R: lingfengsan/M ...

  8. c#分页_使用Kotlin搭配Springboot开发RESTFul接口(二)自定义配置、跨域、分页

    前言 上一篇文章请看这里:使用Kotlin搭配Springboot开发RESTFul接口与服务部署 上一篇文章介绍了Kotlin搭配Springboot的开发流程,从搭建项目.ORM.Controll ...

  9. java存储过程示例_安全密码存储–请勿做的事和Java示例

    java存储过程示例 安全存储密码的重要性 作为软件开发人员,我们最重要的职责之一就是保护用户的个人信息. 如果没有我们应用程序的技术知识,用户别无选择,只能相信我们正在履行这一责任. 令人遗憾的是, ...

最新文章

  1. vue开发使用vue-particles如何兼容IE11?
  2. MySQL查看表结构的实际操作命令简介
  3. leetcode 606. Construct String from Binary Tree | 606. 根据二叉树创建字符串
  4. ps -ef 输出结果的具体含义
  5. 网络协议从入门到底层原理(8)HTTPS(成本、通信过程、TLS1.2的连接,配置服务器HTTPS)
  6. 从传统企业谈大数据的战略意义
  7. CentOS - thin web server for Ruby(centos下安装thin,运行rails)
  8. java做度量衡换算器,磅换算计算器(公斤和磅在线换算器)
  9. Win10开电脑热点以后手机连接会IP配置失败或者一直显示获取IP中
  10. 使用adb命令管理应用
  11. 逆向加固的apk详细教程
  12. 自学总结:非科班转行前端拿到字节跳动 offer?看我是如何一步一步做到的?
  13. 苹果Mac 软件出现意外退出解决方法
  14. 盘点机器人四大家族——KUKA机器人
  15. 70后.net老猿,尚能饭否?
  16. Vivado:【1】Vivado 2018.3 配置ModelSim仿真
  17. 布法罗大学计算机硕士学费,纽约布法罗大学学费是多少
  18. 再讲卷积的本质及物理意义,解释的真幽默!
  19. 打造一套安全的UI组件库!
  20. matlab 水波模拟 代码,matlab - 在Matlab中模拟一艘在水波中航行的船 - SO中文参考 - www.soinside.com...

热门文章

  1. 牛客网【每日一题】7月30日题目精讲—Xor Path
  2. AT2368-[AGC013B]Hamiltonish Path【构造】
  3. AT3949-[AGC022D]Shopping【贪心】
  4. nssl1454-最短路【并查集,贪心】
  5. jzoj6297-世界第一的猛汉王【切比雪夫距离,扫描线】
  6. jzoj4788-[NOIP2016提高A组模拟9.17]序列【差分,贪心】
  7. 【做题记录】 [JLOI2011]不等式组
  8. 10、mybatis中缓存的使用
  9. 41、java应用占用cpu过高原因分析
  10. Hadoop生态hive(六)Hive QL表