Serializable 和Parcelable 的区别(Android每日面试题)

3,975 阅读5分钟

前言

看见即降服,这句话说的是一件事物,只要你看得到,你就能得到。

对我来说记录就是看见。

面试题不只是为了面试,更是为了帮助我们更深入地理解我们已知的知识。

自我检讨

本篇文章中的引用稍微多了一下(额,好吧,好像我每篇文章都有好多引用),请大家谅解,不过引用的文章确实是我想要的内容,讲得也挺好的,希望大家可以去阅读一下,帮助自己理解。

序列化

对于本文的这个问题,我觉得我们得先了解序列化这个概念,什么是序列化(反序列化)?序列化有什么作用?怎么实现序列化?Ok,灵魂三连问!

什么是序列化(反序列化)

具体学术级别的概念可以阅读文末参考。我在这里用我的理解来简单描述下:

  • 序列化:当我们需要把程序内存中new Person(18,"小明")这个对象存储下来(如放到磁盘的文件)或者用于网络传输时,我们必须将这个对象流化(也就是将对象变为有序的字节流),这个过程就是序列化。那么问题来了,为什么要流化呢?因为只有流化的对象,才能被传输,被存储。咦?我这个解释怎么怪怪的?好吧,流化以后的对象的真容大家可以看一下文末参考文章的最后,它是一串字节流,所以就可以被网络传输,被存储啦。不晓得有没有讲清楚?(大家可以读一下这篇文章的What部分).
  • 反序列化:反序列化就是序列化的反操作,就是把序列化生成的字节流转为我们内存的对象。

序列化有什么作用

这个作用以及在上面提到过了,用于网络传输和存储。

怎么实现序列化

两种方式:

1.实现Serializable接口

2.实现Parcelable接口

Serializable

首先这个接口是Java自带哦。

怎么使用呢?很简单,大家也都知道的,只需要给我们需要序列化的类实现这个接口就行了(实现这个接口就代表我们的类可以被序列化/反序列化),然后就可以使用ObjectOutputStream序列化和ObjectInputStream反序列化了。(具体的可以参考这篇文章)

关于什么时候使用transientserialVersionUID怎么用,大家可以阅读下这篇文章

Serializable的底层原理,也就是ObjectOutputStreamObjectInputStream到底做了什么,大家可以阅读这篇文章的Why部分

Parcelable

这个接口是Android专有的。这里额外多说一句,当我们需要将我们的对象进行网络传输或存储到文件中时,使用Serializable;当我们需要将我们的对象在进程间传递通信时,使用Parcelable(文末有解释)。

使用方式:实现Parcelable接口,重写describeContents()writeToParcel(Parcel dest, @WriteFlags int flags),并添加一个静态成员变量CREATOR,这个变量还需要实现Parcelable.Creator接口。

在说Parcelable的底层原理之前,我们需要了解一下Parcel这个类,知道了它就知道Parcelable的底层原理。这里是Parcel的使用和实现,大家看完应该就能清楚Parcelable底层是如何序列化/反序列化的。

区别

在我们谈论区别之前我们先看下这个SO的帖子,看下老外的解释。

  1. Parcelable的效率要快于Serializable(这是最主要的区别)。这个结论的解释可以看这个(一定要看!)。好吧,我在下面也简单解释下吧:

    a.Serializable底层实现需要用到反射(你要是不知道哪里用到了反射,请再看一下上面提到的Serializable底层原理引用到文章中的why部分),而且也会产生大量的对象(这可能会触发GC);再者就是Serializable是在IO操作(这句话应该没有什么太大疑问吧,上面提到过它的实现是使用ObjectOutputStreamObjectInputStream的)。

    b.Parcelable底层实现则不需要反射,而且它是内存操作。至于为什么它是内存操作,除了阅读上面的Parcel的使用和实现,我觉得要是再了解一下binder的实现原理或者Activity的启动流程(启动流程其实就用到了进程间通信,用到进程间通信,那么就会用binder)可能会更好的理解。

  2. Parcelable的使用要复杂于Serializable(这个就不用解释了吧)。

好了,最后解释一下,为什么IPC的时候用Parcelable,网络传输和保存至磁盘的时候用Serializable。还是先来一个文章引用,然后我自己再解释一下。

  • IPC的时候用Parcelable,是因为它效率高,虽然我们在使用Intent传递的时候也可以使用Serializable的对象。
  • 网络传输和保存至磁盘的时候用Serializable,是因为Parcelable不能保证,当外部条件发生变化时数据的连续性。也可以看官网对Parcel的解释:

As such, it is not appropriate to place any Parcel data in to persistent storage: changes in the underlying implementation of any of the data in the Parcel can render older data unreadable.

参考

cloud.tencent.com/developer/a…