应用程序中的对象存储在内存中,如果我们想把对象存储下来或者在网络上传输,这个时候就需要用到对象的序列化和反序列化。

对象序列化就是把一个 Object 对象所有的信息表示成一个字节序列,这包括 Class 信息、继承关系信息、访问权限、变量类型以及数值信息等。

 

Serializable

Java中的序列化Serialable高级详解

Android序列化完全解析

Serializable 是 Java 原生的序列化机制,在 Android 中也有被广泛使用。我们可以通过 Serializable 将对象持久化存储,也可以通过 Bundle 传递 Serializable 的序列化数据。

Serializable 的原理是通过 ObjectInputStream 和 ObjectOutputStream 来实现的。

整个序列化过程使用了大量的反射和临时变量,而且在序列化对象的时候,不仅会序列化当前对象本身,还需要递归序列化对象引用的其他对象。

注意事项

不被序列化的字段。类的 static 变量以及被声明为 transient 的字段,默认的序列化机制都会忽略该字段,不会进行序列化存储。当然我们也可以使用进阶的 writeReplace 和 readResolve 方法做自定义的序列化存储。

serialVersionUID。在类实现了 Serializable 接口后,我们需要添加一个 Serial Version ID,它相当于类的版本号。这个 ID 我们可以显式声明也可以让编译器自己计算。通常我建议显式声明会更加稳妥,因为隐式声明假如类发生了一点点变化,进行反序列化都会由于 serialVersionUID 改变而导致 InvalidClassException 异常。

构造方法。Serializable 的反序列默认是不会执行构造函数的,它是根据数据流中对 Object 的描述信息创建对象的。如果一些逻辑依赖构造函数,就可能会出现问题,例如一个静态变量只在构造函数中赋值,当然我们也可以通过进阶方法做自定义的反序列化修改。

 

Parcelable

Android序列化完全解析

由于 Java 的 Serializable 的性能较低,Android 需要重新设计一套更加轻量且高效的对象序列化和反序列化机制。Parcelable 正是在这个背景下产生的,它核心的作用就是为了解决 Android 中大量跨进程通信的性能问题。

Parcelable 只会在内存中进行序列化操作,并不会将数据存储到磁盘里。

注意事项

系统版本的兼容性。由于 Parcelable 设计本意是在内存中使用的,我们无法保证所有 Android 版本的Parcel.cpp实现都完全一致。如果不同系统版本实现有所差异,或者有厂商修改了实现,可能会存在问题。数据前后兼容性。

Parcelable 并没有版本管理的设计,如果我们类的版本出现升级,写入的顺序及字段类型的兼容都需要格外注意,这也带来了很大的维护成本。

 

Serial

Serial是Twitter出品的高性能序列化方案,它力求帮助开发者实现高性能和高可控的序列化过程。

由于没有使用反射,相比起传统的反射序列化方案更加高效。

开发者对于序列化过程的控制较强,可定义哪些 Object、Field 需要被序列化。

有很强的 debug 能力,可以调试序列化的过程。

有很强的版本管理能力,可以通过版本号和 OptionalFieldException 做兼容。

 

数据的序列化

JSON

相比对象序列化方案,速度更快,体积更小。

相比二进制的序列化方案,结果可读,易于排查问题。

使用方便,支持跨平台、跨语言,支持嵌套引用。

 

Protocol Buffers

Google Protocol Buffer 的使用和原理

性能。使用了二进制编码压缩,相比 JSON 体积更小,编解码速度也更快

兼容性。跨语言和前后兼容性都不错,也支持基本类型的自动转换,但是不支持继承与引用类型。

使用成本。Protocol Buffers 的开发成本很高,需要定义.proto 文件,并用工具生成对应的辅助类。辅助类特有一些序列化的辅助方法,所有要序列化的对象,都需要先转化为辅助类的对象,这让序列化代码跟业务代码大量耦合,是侵入性较强的一种方式。