维基百科上对于序列化的解释是保存数据为可被取用的格式,而反序列化就是指取用这些数据。把文本复制到电脑的剪切板,把各种文件保存到硬盘都可被称为序列化
序列化指的是保存数据的过程,所以实现Serializable、Parcelable接口不是序列化,而是让对象可以被序列化
Java中的序列化指的是把数据保存为可被其他进程读取的格式,Java的序列化相关的类把数据以某种格式保存,而其他进程可以用这些类把数据读取出来,相当于是一种数据写入读取的协议,如果每个应用程序都自己来实现序列化那将很乱且不通用,所以使用Java提供的序列化方式
序列化是针对对象的,而静态成员变量属于类而不是属于对象,所以静态成员变量不参与序列化
Serializable
Java 提供的序列化方法,不推荐在android中使用
使用方法很简单,只需要实现这个Serializable接口即可,而它也没有什么需要实现或覆盖的方法,只要定义一个long常量即可
private static final long serialVersionUID = 一个数字;
这种序列化的方式不推荐使用,所以我也不写什么demo,这里只解答几个问题
0 为什么需要serialVersionUID
这个值相当于是一个校验码,反序列化的时候比较当前类中的serialVersionUID和序列化数据中的serialVersionUID,如果相同,则反序列化成功,否则失败
静态成员变量不参与序列化,而serialVersionUID参与序列化,这两个说法都来自《android开发艺术探索》,好像有矛盾。我的理解是这是【静态常量】不是【静态变量】,所以它参与序列化,亦或者是因为需要用它做校验?
serialVersionUID的值可以手动指定,随便什么值,也可以用集成开发环境生成的值(如果这个集成开发环境有这个功能的话),没什么区别
如果不设置serialVersionUID
在序列化和反序列化的时候,如果不手动指定serialVersionUID,系统会自动计算这个值,如果序列化存储期间,这个实现Serializable的类被重新编辑(删除或增加成员变量),反序列化的时候计算出来的serialVersionUID值就与原先的不同,导致反序列化失败
如果手动设置这个值,这个类虽然发生了变化,系统还是会反序列化这个对象,尽可能的恢复保存的数据,虽然不可能恢复到被保存的状态了
1 实现这个接口后如何序列化
使用ObjectOutputStream把实现这个接口的对象写入一个文件,就是序列化;用ObjectInputStream把这个文件读取成一个对象,就是反序列化。当然,反序列化的时候需要知道那个文件的路径
2 为什么不推荐这个方式
由上一题可知这种序列化方式伴随大量io操作,效率很低
3 在bundle中使用Serializable为什么不需要序列化
bundle会自动序列化和反序列化Serializable对象,省去了手动将对象写入文件的过程,虽然我没找到这个序列化的具体代码
确切的说bundle会序列化它保存的所有数据,不只是Serializable、Parcelable,还包括其他基本类型
Parcelable
Parcelable是在内存上序列化,当然也可以把对象序列化到存储设备或者同伙网络传输,但是这两种情况下用Parcelable会比较复杂,推荐使用Serializable
Parcelable对象是可被序列化的对象
Parcel对象是保存Parcelable对象序列化后的数据的容器,它可以在进程间传递,Parcelable则不行
demo如下
public class MyP implements Parcelable {
private String str1;
private String str2;
public MyP(String str1, String str2) {
this.str1 = str1;
this.str2 = str2;
}
public String getStr1() {
return str1;
}
public String getStr2() {
return str2;
}
//这下面就是要实现的东西,
public static final Creator<MyP> CREATOR = new Creator<MyP>() {
//在这里返回一个【我自定义的实现Parcelable接口】的对象
//调用Parcel的read方法实现反序列化
@Override
public MyP createFromParcel(Parcel in) {
return new MyP(in.readString(),in.readString());
}
//这个方法不用改,用系统默认的就行
@Override
public MyP[] newArray(int size) {
return new MyP[size];
}
};
//用一个int值描述当前的Parcelable类型,不用管,直接返回0
@Override
public int describeContents() {
return 0;
}
//调用Parcel的write方法实现序列化
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(str1);
dest.writeString(str2);
}
}