IPC通信基础概念之序列化

一、对象序列化

    何为对象序列化?看着名字就有点抽象。那么官方的解释是:序列化 (Serialization)将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。

   从上面的解释可以粗略的得知序列化就是将对象状态写入到存储区中。那么既然可以写入状态,就可以从存储区中读取对象状态,重新创建状态。也就是所谓的反序列化。

二、为什么要对象序列化

先看一个例子:

假如我有两个类,分别是A和B,B类中含有一个指向A类对象的引用,现在我们对两个类进行实例化{ A a = new A(); B b = new B(); }。这时在内存中实际上分配了两个空间,一个存储对象a,一个存储对象b。接下来我们想将它们写入到磁盘的一个文件中去,那么在写入的时候就会出现一个问题!因为对象b包含对对象a的引用,所以系统会自动的将a的数据复制一份到b中,这样的话当我们从文件中恢复对象时(也就是重新加载到内存中)时,内存分配了三个空间,而对象a同时在内存中存在两份,想一想后果吧,如果我想修改对象a的数据的话,那不是还要搜索它的每一份拷贝来达到对象数据的一致性,耗时又耗费内存。这是不理想的方式。

所以,对象序列化就出来了,很好的解决了这个问题。它具体是通过下面的方式来解决的:

1.保存到磁盘的所有对象都获得一个序列号(1, 2, 3等等)。
2.当要保存一个对象时,先检查该对象是否被保存了。
3.如果以前保存过,只需写入"与已经保存的具有序列号x的对象相同"的标记,否则,保存该对象。

三、实现序列化的两种方式

那么该怎么去实现对象的序列化呢?主要有两种方式,各有优缺点。下面来分析一番:

(一)Serializable接口

Serializable接口是java提供的一个序列化接口,不过它是个空接口,为对象提供标准的序列化和反序列化操作。

使用Serializable来实现序列化很简单。只需要让类继承这个借口并在类的声明中指定一个类似下面的标识即可:

private static final long  serialVersionUID=5651151351613L;

声明这个标识其实和序列化无关,有没有这个标识都可以序列化成功,但是反序列化可能会失败。因为反序列化就是根据这个标识来定位对象的。如果你没有手动指定这个标识,那么编译器也会自动根据当前类的结构生成一个它的hash值。但这种有个弊端:如果当前类的结构发生改变了,比如增加了或删除了某些成员变量,那么系统就会更新它的hash值。这样就出现了一个问题,这个hash值和之前保存的hash值不一样,所以会导致反序列化失败。但手动指定一个serialVersionUID值就可以在很大程度上避免了反序列化的失败。

但还有种特殊的情况手动指定serialVersionUID值也不能保证反序列化成功:那就是如果类结构发生了非常规的改变:比如类名改变了,成员变量的类型改变。虽然serialVersionUID值通过验证但是类结构发生毁灭性的变化,无法从老数据中还原出一个新的类结构对象,所以序列化还是失败。

需要注意点:

1.静态成员变量属于类不属于对象,所以不参与序列化过程。

2.使用transient关键字标识的成员变量不参与序列化过程。

(二)Parcelable接口

Parcelable也是一个接口,只要实现了这个接口,一个类的对象就可以实现序列化并可以通过Intent和Binder传递。

Parcelable的实现方法和功能如下图:

(三)两种方式的区别

那么这两种方式有什么区别呢?

相对于Serializable来说Parcelable的使用方式较为复杂。但是它有一个优点:效率高。

Serializable是java中的序列化接口,使用简单按时开销大,序列化和反序列化需要大量I/O操作。但是Parcelable是Android的序列化方式,更适用于Android平台上。因此我们首选Parcelable。

通过Parcelable方式将对象序列化到存储设备中或者将对象序列化后通过网络传输都是可以的,但过程较复杂,所以在这两种情况下建议使用Serializable方式。

猜你喜欢

转载自blog.csdn.net/king_guoguo/article/details/79772500
今日推荐