关于java的序列化

Python011

关于java的序列化,第1张

首先说明一下序列化的知识:java中的序列化(serialization)机制能够将一个实例对象的状态信息写入到一个字节流中,使其可以通过socket进行传输、或者持久化存储到数据库或文件系统中;然后在需要的时候,可以根据字节流中的信息来重构一个相同的对象序列化机制在java中有着广泛的应用3EJB、RMI等技术都是以此为基础的。序列化机制是通过java.io.ObjectOutputStream类和java.io.ObjectInputStream类来实现的。在序列化(serialize)一个对象的时候l会先实例化一个ObjectOutputStream对象,然后调用其writeObject()方法;在反序列化(deserialize)的时候,则会实例化一个ObjectInputStream对象,然后调用其readObject()方法。上面您的错误,就是在于有一个或者几个没有"序列化"的数据,导致没有办法创建输出流,导致发生的java.io.NotSerializableException。之所以要序列化,我猜测是因为您的数据里面存在一个对象型的数据,但是该对象没有实现序列化。比如:您有一个字段为address,这个字段您是通过一个类Address来描述的,Address里面可能有province、city、street等等属性或者一些setter 和getter,如果这个类,没有实现序列化,往往会出现这个问题毕竟没有看到程序,是我的一个猜测,请检查一下程序或者发出来进行进一步讨论。

序列化(serialization)在计算机科学的数据处理中,是指将数据结构或对象状态转换成可取用格式(例如存成文件,存于缓冲,或经由网络中发送),以留待后续在相同或另一台计算机环境中,能恢复原先状态的过程。依照序列化格式重新获取字节的结果时,可以利用它来产生与原始对象相同语义的副本。对于许多对象,像是使用大量引用的复杂对象,这种序列化重建的过程并不容易。面向对象中的对象序列化,并不概括之前原始对象所关系的函数。这种过程也称为对象编组(marshalling)。从一系列字节提取数据结构的反向操作,是反序列化(也称为解编组、deserialization、unmarshalling)。

序列化在计算机科学中通常有以下定义:

序列化与反序列化为数据交换提供了可能,但是因为传递的是字节码,可读性差。在应用层开发过程中不易调试,为了解决这种问题,最直接的想法就是将对象的内容转换为字符串的形式进行传递。具体的传输格式可自行定义,但自定义格式有一个很大的问题——兼容性,如果引入其他系统的模块,就需要对数据格式进行转换,维护其他的系统时,还要先了解一下它的序列化方式。为了统一数据传输的格式,出现了几种数据交换协议,如:JSON, Protobuf,XML。这些数据交换协议可视为是应用层面的序列化/反序列化。

如前所述,序列化和反序列化的出现往往晦涩而隐蔽,与其他概念之间往往相互包容。为了更好了让大家理解序列化和反序列化的相关概念在每种协议里面的具体实现,我们将一个例子穿插在各种序列化协议讲解中。在该例子中,我们希望将一个用户信息在多个系统里面进行传递;在应用层,如果采用 .net 语言,所面对的类对象如下所示:

JSON中的元素都是键值对——key:value形式,键值对之间以":"分隔,每个键需用双引号引起来,值的类型为String时也需要双引号。其中value的类型包括:对象,数组,值,每种类型具有不同的语法表示。

基础类型

对象

数组

说到XML就不得不介绍下SOAP(Simple Object Access protocol),SOAP 是一种被广泛应用的,基于 XML 为序列化和反序列化协议的结构化消息传递协议。SOAP 在互联网影响如此大,以至于我们给基于 SOAP 的解决方案一个特定的名称 --Web service。SOAP 虽然可以支持多种传输层协议,不过 SOAP 最常见的使用方式还是 XML+HTTP。SOAP 协议的主要接口描述语言(IDL)是 WSDL(Web Service Description Language)。SOAP 具有安全、可扩展、跨语言、跨平台并支持多种传输层协议。如果不考虑跨平台和跨语言的需求,XML 的在某些语言里面具有非常简单易用的序列化使用方法,无需 IDL 文件和第三方编译器

实际使用中具体要使用哪个协议,我们可以从上列出的几个特性进行综合考虑

序列化协议一方面要能摆脱语言、平台的束缚;另一方面要在业界耳熟能详应用广泛。比如Java标准的对象序列化实现就不是这一条的好榜样,你要一个C程序员将Java标准序列化实现的数据反序列化成对应结构体是一个很蛋疼的事情。相反,JSON就是一个很好的序列化协议,至少在这一条上算得上是佼佼者了。

序列化协议要能方便开发过程中的调试。做过二进制协议开发的同学一定深有体会,肉眼基本不可辨别序列化后的数据,需要借助一些第三方的工具一点点分析。相对于二进制协议,文本协议就比较和蔼可亲了。

协议要能够经得住时间的考验。一般情况下采用公开流行的协议是不存在这个问题的,因为他们都被成千上万的应用检验过了。特别要小心的是自定义协议,举个反例,比如自定义一个类似于Java标准序列化协议的协议,由于当前业务没有涉及到对象和对象之间的继承关系,所以协议制定者没有考虑对象继承的情况。但是随着业务的发展,系统中出现了继承关系的实体类,某个同事不小心将这种对象的实例序列化,结果可想而知。协议不够成熟,所以自定义协议需要考虑的因数很多。如果自己不是大牛,建议不要自定义序列化协议。

和稳定性差不多,满足通用性条件的协议基本不会出现这个问题。问题还是会出现在自定义协议上。协议的成熟是一个漫长的过程,要经过不断的测试。比如稳定性中出现的那个问题,协议将继承关系的序列化加入,升级之后就能解决问题。但是要做到兼容以前的版本就不那么容易了。协议的制定者也不是圣人,不可能考虑得那么周全,但是一定要有一套可扩展的方案,这样协议才能存活下来,慢慢迭代成稳定版本。

说道性能问题,无非就是时间和空间的博弈。序列化结果数据的大小,直接影响网络传输的带宽和磁盘存储的空间。序列化和反序列化过程所消耗的时间长短,影响系统的性能。几种常用的协议性能的比较网上有很多,这里就不详细介绍了。