首页 课程 师资 教程 报名

实战案例:轻松搞定Java两种序列化机制

  • 2019-09-29 09:26:15
  • 2583次 动力节点



  我们最常使用的创建对象的方式,就是使用new运算符来创建对象,并使用之。比如,如果你有一个Student类,在其构造函数中接受一个人的name,gender和height作为参数,你可以创建一个Student对象,如下所示:


  Studentzhangsan=newPerson("张三","男",6.7);


  如果你想将对象zhangsan保存到文件中,然后在不使用new运算符的情况下将其恢复到内存中,那该怎么做呢?本节就来讨论这个主题内容。


  首先要明白,将内存中的对象转换为字节序列并将字节序列存储在诸如文件的存储介质中的过程称为对象序列化。你可以将字节序列存储到永久存储器中,例如文件或数据库;还可以通过网络传输字节序列。从存储器中读取序列化过程产生的字节序列并将对象恢复到内存中的过程称为对象反序列化。对象的序列化也称为对对象进行压缩或编组。对象的反序列化也称为对对象进行复原或解组。可以将序列化视为将对象从内存写入存储介质,将反序列化视为从存储介质将对象读入内存。

image.png

  完成这两类工作的是ObjectOutputStream类和ObjectInputStream类


  ObjectOutputStream类的对象用于序列化对象。ObjectInputStream类的对象用于反序列化对象。你还可以使用这些类的对象来序列化原始数据类型的值,例如int,double,boolean等。


  ObjectOutputStream和ObjectInputStream类分别是输出和输入流的具体装饰器类(IO族系类中装饰器用的非常之多)。但是,它们不是从它们的抽象装饰器类继承而来的。它们是从各自的抽象组件类继承而来的。ObjectOutputStream继承自OutputStream,ObjectInputStream继承自InputStream。貌似这与装饰模式不一致的。其实,这仍然适合装饰器模式(这里就不展开了)。


  关于对象序列化,你的需要序列的对象的类,其必须实现Serializable或Externalizable接口,只有这样了,才能进行序列化或反序列化。Serializable接口是一个标记接口(没有任何成员)。如果希望序列化Student类的对象,则需要按如下方式声明Student类:

       image.png

  序列化时,由Java负责从(向)流读取(写入)Serializable对象的细节,而你只需要将对象传递给(从)流,调用相应方法把对象写入(读取)到流中即可。


  若你的类实现了Externalizable接口,可以更好地控制从流中读取对象和写入对象。该接口继承了Serializable接口。声明如下:

      image.png

  从流中读取对象时,将调用readExternal()方法。将对象写入流时,将调用writeExternal()方法。但你必须分别编写逻辑来读取和写入readExternal()和writeExternal()方法中的对象字段。实现Externalizable接口的类示例如下:

      image.png

image.png

  下面进入序列化和反序列化的具体内容。


  2.对象序列化


  要序列化对象,需要执行以下步骤:

      image.png

  通过将ObjectInputStream类用作另一个输入流的装饰器来创建ObjectInputStream类的对象,该输入流表示存储序列化对象的存储介质。例如,要从Student.ser文件中读取对象,请按如下方式创建对象输入流:

      image.png


  要从ByteArrayInputStream中读取对象,请按如下方式创建对象输出流:

      image.png

  使用ObjectInputStream类的readObject()方法反序列化对象,就像这样:

      image.png

  注意:确保以调用writeObject()方法写入对象相同的顺序调用readObject()方法读取对象(什么顺序写入就什么顺序读出)。例如,如果你以object-1,float和object-2顺序写入了三条信息,则必须按相同的顺序读取它们:object-1,float和object-2。


  最后,关闭对象输入流,如下所示:

      image.png

  清单-3演示了如何从Student.ser文件中读取对象。确保当前目录中存在Student.ser文件。否则,程序将打印一条错误消息,其中包含此文件的预期位置。


  清单-3.从文件中读取对象

      image.png

  输出信息如下(和写入的对象一致):

     image.png

  4.Externalizable序列化


  在前面的部分中,我们介绍了如何序列化和反序列化可序列化对象。在本节中,我将向你展示如何用Externalizable序列化和反序列化(Externalizable)对象。我修改了Student类来实现Externalizable接口。我将新类命名为StudentExt,如清单-4所示。

     image.png

  Java将分别将对象输出流和对象输入流的引用传递给StudentExt类的writeExternal()和readExternal()方法。


  在writeExternal()方法中,将name和gender字段写入对象输出流。请注意,height字段不会写入对象输出流。这意味着当你从readExternal()方法中读取流中的对象时,将无法获得height字段的值。writeUTF()方法用于将字符串(name和gender)写入对象输出流。


  在readExternal()方法中,可从流中读取name和gender字段,并在name和gender实例变量中设置它们。


  清单-5和清单-6包含StudentExt对象的序列化和反序列化逻辑。


  清单-5.序列化实现了Externalizable接口的StudentExt对象

     image.png

  运行程序输出信息如下:

    image.png

  清单-6.反序列化实现了Externalizable接口的StudentExt对象

    image.png

  输出结果如下:

    image.png

  清单-6的输出演示了在反序列化StudentExt对象后,height字段的值是默认值(Double.NaN)。


  以下是使用Externalizable接口序列化和反序列化对象的步骤:


  1.当调用writeObject()方法来写入Externalizable对象时,Java(执行引擎)会将对象的标识写入到输出流中,然后调用其类的writeExternal()方法。你可以在(序列化对象类的)writeExternal()方法中将与对象相关的数据写入输出流。如果需要,可以完全控制在此方法中写入流的对象的相关数据。如果要存储某些敏感数据,可能需要先将其加密,然后再将其写入流中,并在从流中读取数据时对其进行解密。


  2.当调用readObject()方法读取Externalizable对象时,Java会从流中读取对象的标识。请注意,对于Externalizable对象,Java仅将对象的标识写入到输出流,而不是有关其类定义的任何详细信息。Java使用对象类的no-args构造函数来创建对象。这就是你必须为一个Externalizable对象提供一个无参(no-args)构造函数的原因。它调用对象的readExternal()方法,以便在此可以完成填充或装配对象的相关字段值。


  对于Serializable对象,JVM仅序列化未声明为瞬态的实例变量。


  以上就是动力节点java培训机构小编介绍的“实战案例:轻松搞定Java两种序列化机制”的内容,希望对大家有帮助,更多java最新资讯请继续关注动力节点java培训机构官网,每天会有精彩内容分享与你。



选你想看

你适合学Java吗?4大专业测评方法

代码逻辑 吸收能力 技术学习能力 综合素质

先测评确定适合在学习

在线申请免费测试名额
价值1998元实验班免费学
姓名
手机
提交