第一个问题,Serializable和Parcelable是什么?
Serializable和Parcelable都是实现序列化/反序列化操作的名称,那么什么是序列化操作?从功用来说,当我们编写代码时会有这样一个需求,一个对象从Activity_A跳转到Activity_B时,需要传递一个obj类型的数据,而计算机基础告诉我们,在计算机中任何数据都是以二进制来保存和传递的,而八种基础的数据类型对应的是Ascell编码(或者是Unicode),本身就有能力转成二进制,而obj自定义的对象是事先无法转换的,因此提供一种名为序列化的方案来帮助开发者快速转换obj与二进制的类型,反序列化自然就是二进制还原成obj。
第二个问题,既然是序列化为什么要提供多种,一个标准岂不是更好?
这里分为两种情况,一是在操作内存传递数据,比如进程间或者是网络传递obj;一种是持久化的操作,将一个obj对象存储在硬盘上,下面分别对两者进行详细说明:
Serializable
首先我们知道Serializable是什么了,当然会继续关心怎么用,也是特容易,哪个obj需要实现序列化直接实现这个接口就好,所以两者相比它的好处非常明显,简单易用,我们来稍微看看(就是从java层面)实现原理,当追踪源码会发现Serializable里是个空接口,什么都没有,这说明什么,序列化的操作根本不是java代码去做的,我们可以这么理解,实现Serializable接口就是在这个类的info上打一个标识,当jvm检测到类的这个标识,就会帮助这个obj去做序列化的操作,举个例子就是,在中小学的课堂上,我不会做数学题怎么办?举手,让老师帮助我做,这个举手就算是一个标识信息,类似于实现serializable接口。
在实现Serializable接口之后,还应该去设置一个serialVersionUID,这个UID的作用就是序列化以后的UID要和当前反序列化准备好的类中的UID相同,这时候才能反序列化成功,这个serialVersionUID的详细工作机制是:在序列化的时候系统将UID写入序列化的文件中,反序列化的时候系统去检测obj类中的UID与序列化文件中的UID是否对应。在Serializable接口说明文档中有一句(在lines153)我们能看到,当我们没有声明serialVersionUID时,系统会帮我们默认设置一个,但是在这里建议开发者自己设置一个UID,有时候默认的UID会在修改obj之后反序列化报错(invalidClassException,有异常可以从这方面考虑考虑,举个例子,我们序列化了一个User类到硬盘上,然后在应用程序中将User的成员变量或者方法值给改了,这时UID值是会被系统改变的,这样两个UID就不匹配了,一定会报错),。
当给obj实现一个Serializable接口,将这个obj,写入硬盘文件(使用ObjectOutPutStream.writeObject(obj))就是一个序列化操作,再从硬盘读出来((Obj)ObjectInPutStream.readObject()),就是反序列化操作
Parcelable
接下来说说Parcelable的使用,Parcelable主要用于进程或网络中传递obj,android系统架构中Binder传递数据就是用Parcel来打包数据进行IPC传输,分为三步:
- 序列化,writeToParcel
- 反序列化,Creator,CreateFromParcel(Parcel){return obj;}
- 状态描述,describeContents
源码中有一个例子我们可以拿来学习,然后直接使用
public class MyParcelable implements Parcelable {
private int mData;
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel out, int flags) {
out.writeInt(mData);
}
public static final Parcelable.Creator<MyParcelable> CREATOR
= new Parcelable.Creator<MyParcelable>() {
public MyParcelable createFromParcel(Parcel in) {
return new MyParcelable(in);
}
public MyParcelable[] newArray(int size) {
return new MyParcelable[size];
}
};
private MyParcelable(Parcel in) {
mData = in.readInt();
}
而实际上,Parcel机制是通过一系列操作,锁定一块memory,让不同进程通过Binder机制进行r/w操作
既然说到了这个序列化,大家还能思考一下数据拷贝有哪几种?深拷贝与浅拷贝。有哪些区别,分别是怎么实现,应用于哪些不同场景?